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


Printk - часть 5


memcpy (log_buf+x, p, n); p += n;

if (log_size < LOG_BUF_LEN) log_size += n; else { wrapped = 1; log_start += n; log_start &= LOG_BUF_LEN - 1; } } while (p < buf_end);

Не следует забывать, что цикл, как правило, выполняется один раз; большее количество выполнений цикла имеет место тогда, когда запись по достижении конца log_buf переходит на начало. Следовательно, log_size и log_buf обновляются только один раз (или два, если случается переход на начало).

Ускорение достигнуто, но мы не будем поступать таким образом по двум причинам. Во-первых, ядро имеет собственную версию memcpy, и мы должны быть четко уверены, что вызов memcpy никогда не приведет к возврату в printk. (Некоторые версии ядра определяют собственные более быстрые версии memcpy, поэтому они должны быть согласны с последним утверждением.) Если memcpy обращается к printk для выдачи уведомления об ошибке, есть риск попасть в бесконечный цикл.

Однако не это самая большая проблема. Самое печальное, что версия цикла, реализованная в ядре, отслеживает также символы новой строки, так что применение memcpy для копирования всего сообщения в log_buf оказывается некорректным — при появлении символа новой строки, он попросту «перепрыгивается».

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

/* В разделе объявлений */ int n; char * start; static char * log = log_buf; /* . . . */

for (start = p; p < buf_end; p++) { *log++ = *p; if (log >= (log_buf + LOG_BUF_LEN)) log = log_buf; /* Wrap. */ if (*p == '\n') { line_feed = 1; break; } }

/* p - start представляет количество копируемых символов */ n = p - start; logged_chars += n; /* * Задание для читателя: * Воспользуйтесь n для обновления log_size и log_start * (Это не так просто, как может показаться на первый взгляд) */

(Следует отметить, что оптимизатор gcc достаточно интеллектуален, чтобы определить, что выражение log_buf + LOG_BUF_LEN внутри цикла не изменяется, поэтому никакого выигрыша от выноса этого выражения за пределы цикла не будет.)

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





- Начало -  - Назад -  - Вперед -



Книжный магазин