OberonCore https://forum.oberoncore.ru/ |
|
Kernel.Time https://forum.oberoncore.ru/viewtopic.php?f=2&t=1283 |
Страница 1 из 1 |
Автор: | Сергей Губанов [ Четверг, 18 Декабрь, 2008 15:49 ] |
Заголовок сообщения: | Kernel.Time |
Как известно, тики в Блэкбоксе 64-битные и получаются из 32-битных KERNEL32.GetTickCount() по следующему алгоритму: Код: PROCEDURE Time* (): LONGINT; VAR t: INTEGER; BEGIN t := KERNEL32.GetTickCount(); IF t < told THEN INC(shift) END; told := t; RETURN shift * 100000000L + t END Time; (Я этот алгоритм передрал к себе в C#) Так вот. Есть подозрение, что с функцией KERNEL32.GetTickCount() могут быть грабли... Подозрения основаны на том, что в .Net ей соответствует функция System.Environment.TickCount, а её значения могут плавать на многопроцессорной машине, в чём я сегодня убедился лично. На 16 процессорной машине (Intel Xeon E7340, Linux SS 2.6.18, Mono 1.2), несколько раз в секунду функция System.Environment.TickCount выдаёт значение на 1 тик меньше значения которое она только что выдала в другом потоке. У меня был код аналогичный приведёному выше (разумеется с блокировками) так вот когда время шло на 1 тик вспять, то глобальный счётчик инкрементировался на четыре миллиарда ![]() ![]() ![]() |
Автор: | Valery Solovey [ Четверг, 18 Декабрь, 2008 17:20 ] |
Заголовок сообщения: | Re: Kernel.Time |
Непонятно что-то. Там несколько машин или несколько процессоров? Если несколько процессоров, то причём тут время? Они же ко времени отношения не имеют. Или там было много потоков, дёргавших счётчик? Хотя всё равно не понятна разница на 1 мс. Контекст, вроде, так быстро переключиться не может. |
Автор: | Сергей Губанов [ Пятница, 19 Декабрь, 2008 13:57 ] |
Заголовок сообщения: | Re: Kernel.Time |
Одна машина. У неё 8 процессоров с гипертредингом, итого 16 логических процессоров. Работают несколько потоков. Каждый поток хочет знать сколько сейчас 64-битных тиков. Поток обращается к этой функции (из предыдущего сообщения). Функция разумеется защищена эксклюзивным блоком (одновременно к ней разрешено обращение только из одного потока). Несколько раз в секунду значение возвращаемое функцией прыгает вверх на четыре миллиарда тиков. Стал разбираться. Оказалось, что значения выдаваемые функцией System.Environment.TickCount не растут монотонно, а несколько раз в секунду бывают на 1 тик меньше предыдущего, т.е. плавают. |
Автор: | Сергей Губанов [ Пятница, 19 Декабрь, 2008 14:03 ] |
Заголовок сообщения: | Re: Kernel.Time |
>> Контекст, вроде, так быстро переключиться не может. Может. Вызываете в одном потоке Sleep(0) и контекст переключается на второй поток. Во втором потоке опять вызываете Sleep(0) и контекст переключается на третий поток и т.д.. Так за 1 ms несколько сотен раз можно контекст переключить. |
Автор: | Valery Solovey [ Пятница, 19 Декабрь, 2008 15:04 ] |
Заголовок сообщения: | Re: Kernel.Time |
По-моему, скорость переключения потоков в лучшем случае - один такт системной шины. Чтобы переключиться на другой поток потребуется обратиться к ОЗУ. В вырожденном случае контекст может сохраниться в кэше (и восстановиться оттуда), но я не знаю, будет ли это влиять на скорость переключения потоков. По поводу времени в обратном направлении. А не могут ли потоки не вовремя засыпать? Сначала отпишется последний поток, затем предпоследний, затем первый из обращавшихся к счётчику времени... |
Автор: | Сергей Губанов [ Пятница, 19 Декабрь, 2008 19:14 ] |
Заголовок сообщения: | Re: Kernel.Time |
>> А не могут ли потоки не вовремя засыпать? Внутри критической секции-то? Да могут, но это ни на что не влияет. Всё равно внутрь критической секции никто не войдёт пока он не проснётся и не выйдет из неё. Инициализация: Код: long ticks = 0; uint old = (uint)GetTickCount(); Вычисление нового значения ticks устойчивое к ошибке операционной системы: Код: Lock(); uint t = (uint)GetTickCount(); uint dt = t - old; if (dt < int.MaxValue) { old = t; tiks += dt; } else { Log.Fatal("Floating time system error."); } Unlock(); Предполагается, что этот код вызывается чаще чем один раз в две недели, так что разницы dt >= int.MaxValue в обычной ситуации быть не может. |
Автор: | Valery Solovey [ Суббота, 20 Декабрь, 2008 13:28 ] |
Заголовок сообщения: | Re: Kernel.Time |
Как я понимаю, в целях отладки Вы получаете время и выводите его в лог. В данной критической секции в лог вывода нет, значит можно допустить, что поток выходит из неё и засыпает (до вывода в лог). Затем время получает второй поток, выходит из секции, печатается и завершается. Просыпается первый поток... Или такая ситуация в Вашем конкретном случае невозможна (скажем, это было предусмотрено)? |
Автор: | Сергей Губанов [ Суббота, 20 Декабрь, 2008 21:28 ] |
Заголовок сообщения: | Re: Kernel.Time |
1) Я, разумеется, печатал тики в лог внутри эксклюзивного блока. Просто в приведённом здесь коде этого не написал, так как... 2) В приведённом примере кода, доказательством плавания тикометра является осуществляющееся несколько раз в секунду событие вывода Log.Fatal("Floating time system error."); |
Автор: | Valery Solovey [ Понедельник, 22 Декабрь, 2008 11:49 ] |
Заголовок сообщения: | Re: Kernel.Time |
Ну тогда хочется, чтобы это был баг .NET, а не проблемы железа... |
Автор: | Geniepro [ Понедельник, 22 Декабрь, 2008 13:06 ] |
Заголовок сообщения: | Re: Kernel.Time |
Возможно даже, что это проблема не .NET, а Mono. А Вы не пробовали ставить Mono 2? |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |