Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Использование высокоточного таймера QPC в MacOS на процессорах ARM для Delphi и Pascal

Delphi , Синтаксис , Дата и Время

Высокоточное время на Apple Silicon: решение для Delphi и Pascal

В мире разработки на Delphi и Pascal часто возникает необходимость в измерении времени с высокой точностью. Стандартные функции, такие как GetTickCount64, могут быть недостаточно точными, особенно на современных платформах, таких как MacOS на процессорах ARM (Apple Silicon). В этой статье мы рассмотрим проблему получения высокоточного времени в этой среде и предложим решение, основанное на обсуждении, развернувшемся на форуме Lazarus.

Проблема:

Функция GetTickCount64 в SysUtils предоставляет довольно грубое измерение времени (1 мс). Для задач, требующих большей точности, этого недостаточно. На Apple Silicon, как и на других современных платформах, существуют аппаратные таймеры, способные предоставлять время с наносекундной точностью. Однако доступ к ним напрямую затруднен, так как они абстрагированы операционной системой.

Решение:

Обсуждение на форуме Lazarus указывает на несколько возможных решений, основанных на использовании API MacOS:

  1. mach_absolute_time(): Эта функция предоставляет доступ к непрерывно увеличивающемуся счетчику с наносекундным разрешением. Для преобразования "тиков" в наносекунды необходимо использовать функцию mach_timebase_info(), которая возвращает информацию о временной базе системы.

  2. clock_gettime(): POSIX-совместимая функция, предоставляющая доступ к различным системным часам с возможностью указания требуемой точности. Подходит для переносимого кода.

  3. dispatch_time(): Часть Grand Central Dispatch, предназначенная для планирования задач, но также может быть использована для измерения времени.

Пример кода на Object Pascal (Delphi):

Предложенное на форуме решение, использующее mach_absolute_time(), выглядит следующим образом:

{$mode objfpc}
{$modeswitch objectivec1}
{$linkframework CoreServices} // Необходимо для линковки с CoreServices

program MachTimeExample;

uses
  ctypes, MacOSAll, CocoaAll;

var
  timebase: mach_timebase_info_data_t;
  startTime, endTime, elapsedNano: UInt64;

begin
  // Инициализация информации о временной базе
  if mach_timebase_info(@timebase) <> 0 then
  begin
    writeln('Ошибка получения информации о временной базе');
    Exit;
  end;

  // Получение начального времени
  startTime := mach_absolute_time();

  // Выполнение измеряемого кода
  NSProcessInfo.processInfo.sleepForTimeInterval(0.5); // Задержка на 0.5 секунды

  // Получение конечного времени
  endTime := mach_absolute_time();

  // Вычисление прошедшего времени в наносекундах
  elapsedNano := (endTime - startTime) * UInt64(timebase.numer) div UInt64(timebase.denom);

  writeln('Начальное время: ', startTime, ' тиков');
  writeln('Конечное время: ', endTime, ' тиков');
  writeln('Прошло времени: ', elapsedNano, ' наносекунд');
  writeln('             ', elapsedNano / 1000000:0:3, ' миллисекунд');
end.

Пояснения к коду:

  • {$mode objfpc} и {$modeswitch objectivec1}: Необходимы для компиляции кода, использующего Objective-C.
  • {$linkframework CoreServices}: Указывает компилятору на необходимость линковки с фреймворком CoreServices, содержащим необходимые функции.
  • mach_timebase_info_data_t: Структура, содержащая информацию о временной базе. Определена в модуле MacOSAll.
  • mach_timebase_info(@timebase): Вызывает функцию mach_timebase_info для заполнения структуры timebase. Проверка возвращаемого значения позволяет обработать возможную ошибку.
  • mach_absolute_time(): Возвращает текущее значение счетчика времени.
  • NSProcessInfo.processInfo.sleepForTimeInterval(0.5): Пример кода, который нужно измерить. В данном случае, это задержка на 0.5 секунды. В реальном приложении здесь будет ваш код.
  • elapsedNano := (endTime - startTime) * UInt64(timebase.numer) div UInt64(timebase.denom): Вычисляет разницу между начальным и конечным временем в тиках, а затем преобразует ее в наносекунды, используя информацию из структуры timebase.

Альтернативное решение (использование clock_gettime()):

Использование clock_gettime() может быть более переносимым решением, так как это POSIX-стандарт. Пример кода:

{$mode objfpc}
uses
  BaseUnix, Unix;

type
  timespec = record
    tv_sec: time_t;
    tv_nsec: longint;
  end;

function clock_gettime(clock_id: clockid_t; var tp: timespec): longint; cdecl; external libc name 'clock_gettime';

const
  CLOCK_MONOTONIC = 1; // Наиболее подходящий вариант для измерения времени

var
  ts: timespec;
  startTime, endTime: int64;
  elapsedNano: int64;

begin
  // Получение начального времени
  clock_gettime(CLOCK_MONOTONIC, ts);
  startTime := ts.tv_sec * 1000000000 + ts.tv_nsec;

  // Выполнение измеряемого кода
  Sleep(500); // Задержка на 500 миллисекунд

  // Получение конечного времени
  clock_gettime(CLOCK_MONOTONIC, ts);
  endTime := ts.tv_sec * 1000000000 + ts.tv_nsec;

  // Вычисление прошедшего времени в наносекундах
  elapsedNano := endTime - startTime;

  writeln('Прошло времени: ', elapsedNano, ' наносекунд');
  writeln('             ', elapsedNano / 1000000:0:3, ' миллисекунд');
end.

Пояснения к альтернативному коду:

  • BaseUnix, Unix: Необходимые модули для работы с POSIX API.
  • timespec: Структура, представляющая время в секундах и наносекундах.
  • clock_gettime: Функция POSIX API для получения текущего времени.
  • CLOCK_MONOTONIC: Указывает на использование монотонного таймера, который не подвержен корректировкам системного времени. Это наиболее подходящий вариант для измерения времени.
  • Преобразование времени из timespec в наносекунды: ts.tv_sec * 1000000000 + ts.tv_nsec.

Важные замечания:

  • Зависимость от платформы: Предложенные решения зависят от MacOS и POSIX API. Для обеспечения переносимости кода необходимо использовать условную компиляцию ({$IFDEF ...}) и предоставлять альтернативные реализации для других платформ.
  • Точность: Несмотря на то, что API предоставляют наносекундное разрешение, реальная точность измерений может быть ниже из-за ограничений аппаратного обеспечения и операционной системы.
  • Нагрузка на систему: Частые вызовы функций измерения времени могут создавать дополнительную нагрузку на систему. Следует использовать их только тогда, когда это действительно необходимо.
  • Версия компилятора: Для успешной компиляции кода, использующего Objective-C, может потребоваться более новая версия Free Pascal Compiler (FPC), например, 3.3.1 или выше.

Заключение:

Получение высокоточного времени на Apple Silicon в Delphi и Pascal возможно с использованием API MacOS, таких как mach_absolute_time() или clock_gettime(). Предложенные примеры кода демонстрируют основные принципы работы с этими API. При использовании этих решений необходимо учитывать зависимость от платформы, реальную точность измерений и возможную нагрузку на систему. Выбор между mach_absolute_time() и clock_gettime() зависит от конкретных требований к переносимости и точности измерений.

Создано по материалам из источника по ссылке.

В статье рассматривается проблема получения высокоточного времени в Delphi и Pascal на Apple Silicon и предлагаются решения с использованием API MacOS, таких как `mach_absolute_time()` и `clock_gettime()`.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Дата и Время ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 17:14:06
2025-10-02 18:40:07/0.0096089839935303/0