Предположим, что все ядра в моем процессоре имеют одинаковую частоту, технически я могу синхронизировать пары счетчиков системного времени и меток времени для каждого ядра каждую миллисекунду или около того. Затем, основываясь на текущем ядре, с которым я работаю, я могу взять текущий rdtsc
и используя тиковую дельту, деленную на частоту ядра, я могу оценить время, прошедшее с момента последней синхронизации пары счетчиков системного времени и метки времени, и вывести текущее системное время без издержек на системный вызов из моего текущего потока ( при условии, что для извлечения вышеуказанных данных блокировки не нужны).
Это прекрасно работает в теории, но на практике я обнаружил, что иногда я получаю больше тиков, чем я ожидал, то есть, если бы моя частота ядра составляла 1 ГГц, и я использовал пару счетчиков системного времени и метки времени 1 миллисекунду назад, я ожидал увидеть дельту в тиках, который составляет около 10 ^ 6 тиков, но на самом деле я обнаружил, что это может быть где-то между 10 ^ 6 и 10 ^ 7.
Я не уверен, что не так, может кто-нибудь поделиться своими мыслями о том, как рассчитать системное время, используя rdtsc
? Моя главная цель — избежать необходимости выполнять системный вызов каждый раз, когда я хочу знать системное время и иметь возможность выполнять вычисления в пространстве пользователя, которые дадут мне его хорошую оценку (в настоящее время я определяю хорошую оценку в результате с интервалом в 10 микросекунд от реального системного времени.
Не делайте этого, используя себя непосредственно RDTSC
машинная инструкция — (потому что ваш планировщик ОС может перепланировать другие потоки или процессы в произвольные моменты или замедлить время). Используйте функцию, предоставляемую вашей библиотекой или ОС.
Моя главная цель — избежать необходимости выполнять системный вызов каждый раз, когда я хочу узнать системное время
В Linux читайте Время (7) затем используйте clock_gettime (2) что очень быстро (и не требует каких-либо медленных системный вызов) благодаря vdso (7).
В C ++ 11-совместимой реализации просто используйте стандарт <chrono>
заголовок. И стандарт С имеет Часы (3) (дает микросекундную точность). Оба будут использовать в Linux достаточно хорошие функции измерения времени (так косвенно vdso
)
В прошлый раз я измерял clock_gettime
это часто занимало менее 4 наносекунд за звонок.
Идея не лишена смысла, но она не подходит для приложений пользовательского режима, для которых, как @Basile предложил, есть лучшие альтернативы.
Сама Intel предлагает использовать TSC в качестве настенных часов:
Инвариант TSC будет работать с постоянной скоростью во всех ACPI P-, C-. и Т-состояния.
Это архитектурное поведение
Движение вперед. На процессорах с инвариантной поддержкой TSC ОС может использовать TSC для служб таймера
(вместо таймеров ACPI или HPET). Чтения TSC намного более эффективны и не несут накладных расходов, связанных с
кольцевой переход или доступ к ресурсу платформы.
Тем не менее, нужно быть осторожным.
В старых процессорах TSC увеличивается на каждом внутренний Цикл часов, это были не настенные часы.
Цитата Intel
Для процессоров Pentium M (семейство [06H], модели [09H, 0DH]); для процессоров Pentium 4, процессоров Intel Xeon
(семейство [0FH], модели [00H, 01H или 02H]); и для процессоров семейства P6: увеличение счетчика меток времени
с каждым тактом внутреннего процессора.Внутренний тактовый такт процессора определяется текущим отношением частоты ядра к частоте шины. Intel®
Переходы технологии SpeedStep® также могут влиять на тактовую частоту процессора.
Если у вас есть только вариант TSC, измерения ненадежны для отслеживания времени.
Хотя есть надежда на инвариантный TSC.
Все еще цитирую Intel
счетчик отметок времени увеличивается с постоянной скоростью. Этот показатель может быть установлен
максимальное отношение тактовой частоты ядра к тактовой частоте процессора или может быть установлено максимальной разрешенной частотой в
какой процессор загружается. Максимальная разрешенная частота может отличаться от базы процессора
частота.
На некоторых процессорах частота TSC может не совпадать
как частота в строке бренда.
Вы не можете просто взять частоту, написанную на коробке процессора.
Увидеть ниже.
rdtsc
не сериализуетсяВам нужно сериализовать его сверху и снизу.
Увидеть этот.
Правильная формула
TSC_Value = (ART_Value * CPUID.15H:EBX[31:0] )/ CPUID.15H:EAX[31:0] + K
См. Раздел 17.15.4 руководства Intel 3.
Конечно, вы должны решить для ART_Value
так как вы начинаете с TSC_Value
, Вы можете игнорировать К так как вас интересуют только дельты.
От ART_Value
дельта вы можете получить время, когда вы знаете частоту АРТ. Это дано как К * В где К константа в MSR MSR_PLATFORM_INFO
а также В 100 МГц или 133 + 1/3 МГц в зависимости от процессора.
Как @BeeOnRope отметил, что из Skylake частота кристалла ART больше не является частотой шины.
Фактические значения, поддерживаемые Intel, можно найти в файле turbostat.c.
switch(model)
{
case INTEL_FAM6_SKYLAKE_MOBILE: /* SKL */
case INTEL_FAM6_SKYLAKE_DESKTOP: /* SKL */
case INTEL_FAM6_KABYLAKE_MOBILE: /* KBL */
case INTEL_FAM6_KABYLAKE_DESKTOP: /* KBL */
crystal_hz = 24000000; /* 24.0 MHz */
break;
case INTEL_FAM6_SKYLAKE_X: /* SKX */
case INTEL_FAM6_ATOM_DENVERTON: /* DNV */
crystal_hz = 25000000; /* 25.0 MHz */
break;
case INTEL_FAM6_ATOM_GOLDMONT: /* BXT */
crystal_hz = 19200000; /* 19.2 MHz */
break;
default:
crystal_hz = 0;
}
Это не должно быть проблемой на компьютерах с одним сокетом, но в ядре Linux есть некоторые комментарии о том, что TSC сбрасывается даже в состояниях без глубокого сна.
Там ничего не поделаешь.
Это фактически мешает вам вести хронометраж с TSC.