Что случилось с поведением rdtscp с "половиной забора"?

В течение многих лет процессоры x86 поддерживали rdtsc инструкция, которая читает "счетчик меток времени" текущего процессора. Точное определение этого счетчика со временем менялось, но в современных процессорах это счетчик, который увеличивается с фиксированной частотой относительно времени настенных часов, поэтому он очень полезен в качестве стандартного блока для быстрых, точных часов или измерения времени. взяты небольшими сегментами кода.

Один важный факт о rdtsc инструкция не упорядочена каким-либо особым образом с окружающим кодом. Как и большинство инструкций, он может быть свободно переупорядочен относительно других инструкций, с которыми он не связан зависимостью. На самом деле это "нормально", и для большинства инструкций это просто невидимый способ ускорить ЦП (это просто длинный способ сказать неверное выполнение).

За rdtsc это важно, потому что это означает, что вы можете не синхронизировать код, который вы ожидаете. Например, приведена следующая последовательность1:

rdtsc
mov ecx, eax
mov rdi, [rdi]
mov rdi, [rdi]
rdtsc

Вы можете ожидать rdtsc измерить задержку двух указателей за нагрузкой нагрузки mov rdi, [rdi], На практике, однако, даже если обе эти загрузки занимают время просмотра (100 секунд циклов, если они отсутствуют в кэше), вы получите довольно небольшое чтение для rdtsc пара. Проблема в том, что второй rdtsc не дожидается окончания загрузки, он просто выполняется не по порядку, поэтому вы не синхронизируете интервал, который считаете нужным. Возможно оба rdtsc инструкция фактически выполняется даже до начала первой загрузки, в зависимости от того, как rdi был рассчитан в коде до этого примера.

Пока что это больше похоже на ответ на вопрос, который никто не задавал, чем на реальный вопрос, но я получаю это.

У вас есть два основных варианта использования rdtsc:

  • Как быстрая временная метка, в которой вы обычно не заботитесь о том, как именно он переупорядочивается с окружающим кодом, поскольку у вас, вероятно, нет понятия уровня инструкции, где должна быть взята временная метка.
  • В качестве точного механизма синхронизации, например, в микротесте. В этом случае вы обычно защищаете rdtsc от повторного заказа с lfence инструкция. Для приведенного выше примера вы можете сделать что-то вроде:

    lfence
    rdtsc
    lfence
    mov ecx, eax
    ...
    lfence
    rdtsc
    

    Чтобы обеспечить своевременные инструкции (...не выходить за пределы временной области, а также следить за тем, чтобы инструкции из временной области не входили (вероятно, это не проблема, но они могут конкурировать за ресурсы с кодом, который вы хотите измерить).

Спустя годы Intel посмотрела на нас, бедных программистов, свысока и предложила новую инструкцию: rdtscp, подобно rdtsc он возвращает показания счетчика меток времени, и этот парень делает что-то большее: он читает значение MSR, специфичное для ядра, атомарно с чтением метки времени. В большинстве операционных систем это содержит значение идентификатора ядра. Я думаю, что идея заключается в том, что это значение можно использовать для правильной настройки возвращаемого значения в реальном времени на процессорах, которые могут иметь разные смещения TSC на ядро.

Отлично.

Другое дело rdtscp введено половинное ограждение с точки зрения исполнения вне очереди:

Из руководства:

Инструкция RDTSCP не является командой сериализации, но она ожидает, пока все предыдущие инструкции не будут выполнены, и все предыдущие загрузки не станут глобально видимыми. Но она не ожидает глобальных видимых предыдущих хранилищ, и последующие инструкции могут начать выполнение до чтения операция выполнена.

Так что это как положить lfence перед rdtscp, но не после. В чем смысл этого полуфехтовального поведения? Если вам нужна общая временная метка, и вы не заботитесь о порядке следования инструкций, вам нужно безусловное поведение. Если вы хотите использовать это для синхронизации коротких фрагментов кода, то поведение половинного ограждения полезно только для второго (окончательного) чтения, но не для начального чтения, так как ограничитель находится на "неправильной" стороне (на практике вы хотите ограждения с обеих сторон, но, вероятно, самое важное - иметь их изнутри).

Какой цели служит такое фехтование?


1 В этом случае я игнорирую старшие 32 бита счетчика.

0 ответов

Другие вопросы по тегам