Ядро Linux в комментариях

Calibrate_delay


calibrate_delay — это функция ядра, которая вычисляет значение BogoMIPS.

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

Вычисление количества циклов, приходящихся на один тик таймера, требует начать подсчет как можно более близко к началу тика. Глобальная переменная jiffies (строка ) хранит количество тиков таймера с момента начала подсчета ядром (более подробно об этом рассказывается в ). jiffies обновляется асинхронно в прерывании, т.е. сто раз в секунду. При этом ядро приостанавливает все активные процессы, обновляет эту переменную, после чего возобновляет свою работу с того места, где она была приостановлена. Если этого не сделать, цикл в следующей строке никогда не завершится. Поскольку jiffies объявлена как volatile и ее значение будет изменяться по причинам, невидимым для компилятора, gcc может оптимизировать цикл таким образом, что он никогда не завершится, gcc пока еще не настоль интеллектуален, однако его создатели предпринимают попытки сделать его таковым.

Как раз можно начинать отработку нового тика таймера, который только что совершился. Следующий шаг заключается в организации задержки размером loops_per_sec проходов цикла таймера и выяснении, прошел ли полный тик таймера. Если это так, цикл завершается, в противном случае цикл стартует заново с удвоенным значением loops_per_sec. Именно такая форма цикла связана частично с тем, что существующие компьютеры не могут выполнять цикл задержки где-то около 232 раз в секунду (для 64-разрядных компьютеров — менее 264 раз в секунду).

Теперь ядру известно, что loops_per_sec проходов цикла задержки на данном компьютере выполняется дольше одной сотой доли секунды, поэтому оценка уточняется. Производится двоичный поиск истинного значения loops_per_sec, вначале исходя из предположения, что истинное значение находится в пределах между текущей оценкой и ее половиной — истинное значение не может превышать текущую оценку, однако может быть (вероятнее всего, это так) меньше ее.


Тем же способом, что и ранее, calibrate_delay просматривает, не является ли уменьшенное значение loops_per_sec все еще настоль большим, чтобы отнимать полный тик таймера. Если это так, то правильное значение лежит где-то очень близко к текущей оценке (немного меньше ее). Цикл продолжается с меньшим значением. В противном случае цикл продолжается с большим значением.

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

Ядро выводит подсчитанное число, дабы привести пользователя в трепет. Бросается в глаза явное отсутствие спецификатора формата %f — везде, где это возможно, ядро старается избегать использования операций с плавающей запятой. Выводимые магические числа базируются на 500000, что произрастает из 1 миллиона (операций в секунду), деленного на 2 (количество операций в теле цикла задержки — decl и переход).


Содержание раздела