Есть ли часы с высоким разрешением (наши) в пространстве пользователя (Linux)?

Знаете ли вы какую-либо реализацию C / C ++ (даже если она непереносимая) с часами высокого разрешения (минимум микросекунды) в пользовательском пространстве для Linux?

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

Согласно моему исследованию Red Hat 7.2:

  • std :: chrono :: high_resolution_clock максимальное разрешение - миллисекунды;
  • clock_gettime CLOCK_MONOTONIC и CLOCK_REALTIME выполняются через системный вызов ядра;
  • gettimeofday выполняется через системный вызов ядра;
  • clock_gettime CLOCK_MONOTONIC_COARSE и CLOCK_REALTIME_COARSE выполняются в пространстве пользователя, но максимальное разрешение составляет миллисекунды;

Спасибо.


person rdil2503    schedule 09.07.2019    source источник
comment
Цель состоит в том, чтобы измерить интервал, прошедший для некоторых операций с низкой задержкой. Я измерил, что часы в пространстве ядра вызывают некоторое время всплески задержки. Уловка, чтобы сделать это, состоит в том, чтобы делать много вызовов. Если вы сделаете миллиард звонков, даже если время будет потрачено на секунду, это будет одна секунда на миллиард звонков, так что в среднем это составит 1 наносекунду на звонок. Вы не можете получить более точную информацию, чем это.   -  person NathanOliver    schedule 09.07.2019
comment
Вы говорите, что непереносимые решения - это нормально. Как насчет решений, привязанных к определенному оборудованию, например к определенной архитектуре ЦП?   -  person Some programmer dude    schedule 09.07.2019
comment
да. Я открыт для привязки к определенному оборудованию. Мы используем Intel Xeon.   -  person rdil2503    schedule 09.07.2019


Ответы (2)


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

#include <regex>
#include <string>
#include <fstream>
#include <iostream>

double cpu_base_frequency() {
    std::regex re("model name\\s*:[^@]+@\\s*([0-9.]+)\\s*GHz");
    std::ifstream cpuinfo("/proc/cpuinfo");
    std::smatch m;
    for(std::string line; getline(cpuinfo, line);) {
        regex_match(line, m, re);
        if(m.size() == 2)
            return std::stod(m[1]);
    }
    return 1; // Couldn't determine the CPU base frequency. Just count TSC ticks.
}

double const CPU_GHZ_INV = 1 / cpu_base_frequency();

int main() {
    auto t0 = __builtin_ia32_rdtsc();
    auto t1 = __builtin_ia32_rdtsc();
    std::cout << (t1 - t0) * CPU_GHZ_INV << "nsec\n";
}

Дополнительная информация из документации Intel:

Постоянное поведение TSC гарантирует, что длительность каждого тактового сигнала одинакова, и поддерживает использование TSC в качестве настенного таймера, даже если ядро ​​процессора меняет частоту. Это архитектурное поведение, которое продвигается вперед.

инвариантный TSC будет работать с постоянной скоростью во всех P-, C- и T-состояниях ACPI. Это архитектурное поведение, которое продвигается вперед. На процессорах с неизменной поддержкой TSC ОС может использовать TSC для служб таймера настенных часов (вместо таймеров ACPI или HPET). Чтения TSC намного более эффективны и не требуют накладных расходов, связанных с переходом по кольцу или доступом к ресурсам платформы.

инвариантный TSC основан на инвариантном аппаратном обеспечении хронометража (называемом Always Running Timer или ART), которое работает на тактовой частоте ядра кристалла.

Масштабируемая частота шины кодируется в битовом поле MSR_PLATFORM_INFO [15: 8], а номинальная частота TSC может быть определена путем умножения этого числа на скорость шины 100 МГц.

person Maxim Egorushkin    schedule 09.07.2019