cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
90 stars 0 forks source link

Добавление новых часов и исправление функций сна #437

Open Roman-Koshelev opened 3 years ago

Roman-Koshelev commented 3 years ago

В С++20 сильно расширили зоопарк часов, но так и не сделали то чего хотелось бы.

Проблемма 1.

Сейчас (до с++20 по крайней мере) есть трое часов (system_clock, steady_clock, high_resolution_clock). system_clock - часы реального времени с разрешением ??? В Windows это 100ns, на linux в libc++ 1us (наносекунды обрезаются) а в libstdc++ 1ns steady_clock - монотонные часы с разрешением обычно 1ns high_resolution_clock - непонятные часы которые steady_clock в Microsoft STL и libc++, и system_clock в libstdc++. Как и для чего их можно использовать абсолютно не ясно.

Проблемы:

Чего хочется:

Проблемма 2.

Для того чтобы заснуть с++ предоставляет 2 функции (sleep_for и sleep_until). Обе работают интересным образом. В Microsoft STL функция sleep_for прибавляет к переданному времени clock::now() и делает sleep_until. libc++ и libstdc++ делают наоборот. sleep_until отнимает от переданного времени clock::now() и вызывает sleep_for

Проблемы Microsoft STL:

Проблемы libc++ и libstdc++:

Чего хочется:

apolukhin commented 3 years ago

@Roman-Koshelev

vDSO

В стандарте C++ не прописываются реализации методов, только их поведение. Это решает две проблемы:

Поэтому стандарт опирается на предположение, что разработчики компиляторов и стандартных библиотек будут делать самую эффективную реализацию. Это предположение называется Quality of Implementation или QoI

QoI

Не у всех всегда получается с первого раза сделать идеальную имплементацию. При этом разработчики с радостью принимают патчи и фиксы.

Я проверил для своей системы. В libstdc++ есть код https://github.com/gcc-mirror/gcc/blob/16e2427f50c208dfe07d07f18009969502c25dc8/libstdc%2B%2B-v3/src/c%2B%2B11/chrono.cc#L85-L89 , соответственно если не определён макрос _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL то вызов должен идти в vDSO версию функции в glibc https://github.com/lattera/glibc/blob/master/sysdeps/unix/sysv/linux/clock_gettime.c Локальная сборка libstdc++ макрос _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL не определяет:

grep -r '_GLIBCXX_USE_CLOCK_GETTIME_SYSCALL' /data/gcc_build/
/data/gcc_build/stage1-x86_64-pc-linux-gnu/32/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/c++config.h:/* #undef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL */
/data/gcc_build/stage1-x86_64-pc-linux-gnu/32/libstdc++-v3/config.h:/* #undef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL */
/data/gcc_build/stage1-x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/c++config.h:/* #undef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL */
/data/gcc_build/stage1-x86_64-pc-linux-gnu/libstdc++-v3/config.h:/* #undef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL */
/data/gcc_build/x86_64-pc-linux-gnu/32/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/c++config.h:/* #undef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL */
/data/gcc_build/x86_64-pc-linux-gnu/32/libstdc++-v3/config.h:/* #undef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL */
/data/gcc_build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/c++config.h:/* #undef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL */
/data/gcc_build/x86_64-pc-linux-gnu/libstdc++-v3/config.h:/* #undef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL */
/data/gcc_build/prev-x86_64-pc-linux-gnu/32/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/c++config.h:/* #undef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL */
/data/gcc_build/prev-x86_64-pc-linux-gnu/32/libstdc++-v3/config.h:/* #undef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL */
/data/gcc_build/prev-x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/c++config.h:/* #undef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL */
/data/gcc_build/prev-x86_64-pc-linux-gnu/libstdc++-v3/config.h:/* #undef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL */

Какая именно у вас платформа (версия C++ библиотеки, ядра ОС, версия C библиотеки)? Заведу им багрепорты, если можно поправить.

Точность

По идее, точность можно достать из std::chrono::*_clock::period http://eel.is/c++draft/time#clock.req Она на вашей платформе показывает истину?

sleep_*

Тут всё чудаковато на разных платформах и процессорах http://gcc.1065356.n8.nabble.com/PATCH-v5-2-8-libstdc-futex-Use-FUTEX-CLOCK-REALTIME-for-wait-tp1692640p1788061.html

Если знаете как улучшить ситуацию - пожалуйста пишите и прикладывайте бенчмарки, оформим фиксы в стандартные библиотеки. Бенчмарки можно набросать на коленке вот тут https://quick-bench.com/

Roman-Koshelev commented 3 years ago

Большое спасибо за подробный ответ. По vDSO согласен (не обязательно оно, но хотелось бы чтобы самым оптимальным доступным способом). Про "Точность" мой недосмотр (там все хорошо). Остается только добавить более быстрые версии часов (если они доступны на платформе), чтобы можно было получить самые быстрые часы с разрешением не менее ... . sleep_* поисследую

Roman-Koshelev commented 3 years ago

Попробовал разные функции. Вот результаты nanosleep mean duration 1641857ns realtime_clock_nanosleep mean duration 1065419ns monotonic_clock_nanosleep mean duration 2373212ns realtime_abs_clock_nanosleep mean duration 1155873ns monotonic_abs_clock_nanosleep mean duration 1715776ns sleep_for mean duration 1687494ns

Пока не понял чем сон в абсолютном времени хуже. И почему вообще функции абсолютного сна имеют право переходить на относительный? Это же значит что по-любому придется писать свою реализацию sleep_unit, если хочешь кода независимого от реализации стандартной библиотеки

Bench - https://yadi.sk/d/PJASVaEtqgZkwg

Roman-Koshelev commented 3 years ago

"Какая именно у вас платформа (версия C++ библиотеки, ядра ОС, версия C библиотеки)? Заведу им багрепорты, если можно поправить."

ldd (GNU libc) 2.28 uname -r 4.18.0-193.19.1.el8_2.x86_64 gcc version 7.1.0 x86_64-redhat-linux

apolukhin commented 3 years ago

_COARSE часы быстрее более чем в 100 раз https://quick-bench.com/q/IAaixmnh5wW5_Qe0CdMm4CCV_Pw

image

Roman-Koshelev commented 3 years ago

Боюсь это предложение я сам не напишу)

apolukhin commented 3 years ago

Боюсь это предложение я сам не напишу)

Главное начните, а как поймёте что застряли - говорите и скидывайте результат. Это как правило сильно упрощает мне дальнейшую задачу по доработке... а порой и дорабатывать не надо ;-)

Roman-Koshelev commented 3 years ago

@apolukhin "По идее, точность можно достать из std::chrono::*_clock::period http://eel.is/c++draft/time#clock.req Она на вашей платформе показывает истину?" Нет не показывает. В Microsoft STL std::steady_clock::period == std::nano, хотя на самом деле для получения времени там используются функции _Query_perf_frequency() (говорит сколько тиков в секунде, везде где я проверил это 10^7. Гарантирует что результат постоянен с момента загрузки ПК и до выключения) и _Query_perf_counter() (возвращает те самые тики). Получается что разрешение часов у монотонных часов как и у системных 100ns а не 1 ns

Roman-Koshelev commented 3 years ago

В windows тоже возможна реализация быстрых часов. Например std::time (которая возвращает секунды) в windows, работает со скоростью COARSE часов в linux (примечательно то что glibc не использует вызовы gettimeofday и time которые сильно быстрее, а просто обрезает время взятое из clock_gettime до нужной точности)