Точность std :: chrono :: system_clock против std :: chrono :: stable_clock в реализациях C ++? - PullRequest
0 голосов
/ 18 февраля 2019

Следующая программа:

#include <chrono>
#include <iostream>
#include <vector>

inline uint64_t now() {
    return std::chrono::duration_cast
       <std::chrono::nanoseconds> 
       (std::chrono::system_clock::now()
          .time_since_epoch())
       .count();
}

int main() {
        std::vector<uint64_t> v;
        for (int i = 0; i < 1000; i++)
                v.push_back(now());

        for (int i = 0; i < v.size()-1; i++)
                std::cout << v[i+1] - v[i] << std::endl;
}

печатает числа в диапазоне от 250 до 300 на:

g++ (Ubuntu 8.2.0-7ubuntu1) 8.2.0

с:

Linux 4.18.0-15-generic #16-Ubuntu SMP x86_64 x86_64 x86_64 GNU/Linux

Значение std:: chrono :: system_clock - это наносекундная точность в этой системе (скорее всего, gettimeofday right?).У меня есть несколько вопросов:

  1. Какая разница в этой системе между std::chrono::system_clock и std::chrono::steady_clock?(Да, я знаю, что они указаны по-разному в стандарте, я рассматриваю эту реализацию.)

  2. Является ли ответ одинаковым для всех целей libstdc ++?

  3. Является ли ответ одинаковым для всех целей libc ++?

  4. Является ли ответ одинаковым для целей Windows / MSVC?

1 Ответ

0 голосов
/ 18 февраля 2019

Я не уверен, что вы задаете вопросы, на которые хотите получить ответы.Я вижу, что вы спрашиваете о разнице между постоянными и системными часами, с точки зрения их точности.Второй, судя по одному фрагменту, касается производительности system_clock :: now, duration_cast, vector :: push_back / vector :: insert и (неявного) vector :: resize.

Я попробуючтобы ответить на первый из этих двух, если вы не возражаете:

  • суть этих часов в том, что один (system_clock) хорош для взаимодействия с любым физическим календарем и поэтому иногда может вернуться назад ( с переходом на летнее / зимнее время , когда кто-то или что-то изменяет системное время на машине, см. Разница между std :: system_clock и std :: stable_clock? ), а другое (устойчивый_клок) гарантированно будет идти только вперед и хорош, например, для измерения длительности push_back.
  • нет никаких гарантий относительно разрешения этих часов.Вот почему вы должны сохранять тип длительности часов как можно более разумным и использовать только метод доступа .count () непосредственно перед печатью;но, поскольку нет никаких гарантий относительно используемого периода, вам, вероятно, следует либо
    1. сделать duration_cast для чего-то стабильного,
    2. , либо выполнить какой-нибудь причудливый выбор суффикса, используя точки в качестве аргументов некоторых метапрограмм..
  • нет никаких гарантий относительно значения time_since_epoch (), и до C ++ 20 нет способа сравнивать time_points / продолжительности, принадлежащие двум разным часам
  • и, пожалуйста, помните, нет НИКАКИХ гарантий относительно разрешения периода для любых часов, в любой системе;Я обнаружил трудный путь (написание некоторых причудливых шаблонов), что даже нет гарантии, что период будет делиться на 1000 ... Для одной из часов одна из библиотек использовала 1 более 10 ^ 8 в качестве периода ...

Таким образом, спрашивать о какой-либо конкретной реализации и надеяться, что их константы будут также использоваться в других реализациях - даже для того же поставщика - не рекомендуется.Я бы всегда пытался использовать часы: time_point или его :: duration, или, в крайнем случае, миллисекунды или наносекунды, в зависимости от того, что я измеряю и как быстро могут летать измеряемые вещи.

Также обратите внимание, что есть функции system_clock: :( to / from) _time_t (), которые определенно будут генерировать значение 1 на 1 (в секундах), даже если system_clock :: duration имеет меньший период.

Пересмотренный фрагмент, использующий устойчивый_клок, его время_точки и вызов продолжительности как можно позже, будет:

#include <chrono>
#include <iostream>
#include <vector>

int main() {
        using namespace std::chrono;
        using clock = steady_clock;

        std::vector<clock::time_point> v;
        for (int i = 0; i < 1000; i++)
                v.push_back(clock::now());

        for (size_t i = 0; i < v.size()-1; i++) {
                std::cout
                        << duration_cast<nanoseconds>(
                                v[i+1] - v[i]
                                ).count()
                        << "ns\n";
        }
}

Редактировать: О, и еще одна вещь - в исходном коде ничего нетэто доказало бы, что ваша библиотека использует nano как точку в system_clock.Вы делаете duration_cast (который использует целочисленное деление, если это необходимо) и получаете период из этого, но с другой продолжительностью, что-то вроде duration_cast>, вы также можете получить ненулевое значение где-то ниже самой низкой 1000. Это маловероятно, но, тем не менее, возможно.

Редактировать 2: Sheesh это сложнее .Изменена причина нестабильности system_clock в первой точке маркера.

...