Читаем Архитектура операционной системы UNIX полностью

Рассмотрим в качестве примера программу, приведенную на Рисунке 8.12, измеряющую продолжительность выполнения функций f и g. Сначала процесс, используя системную функцию signal, делает указание при получении сигнала о прерывании вызывать функцию theend, затем он вычисляет диапазон адресов программы, в пределах которых будет производиться измерение продолжительности (начиная с адреса функции main и кончая адресом функции theend), и, наконец, запускает функцию profil, сообщая ядру о том, что он собирается начать измерение. В результате выполнения программы в течение 10 секунд на несильно загруженной машине AT&T 3B20 были получены данные, представленные на Рисунке 8.13. Адрес функции f превышает адрес начала профилирования на 204 байта; поскольку текст функции f имеет размер 12 байт, а размер целого числа в машине AT&T 3B20 равен 4 байтам, адреса функции f отображаются на элементы массива buf с номерами 51, 52 и 53. По такому же принципу адреса функции g отображаются на элементы buf c номерами 54, 55 и 56. Элементы buf с номерами 46, 48 и 49 предназначены для адресов, принадлежащих циклу функции main. В обычном случае диапазон адресов, в пределах которого выполняется измерение параметров, определяется в результате обращения к таблице идентификаторов для данной программы, где указываются адреса программных секций. Пользователи сторонятся функции profil из-за того, что она кажется им слишком сложной; вместо нее они используют при компиляции программ на языке Си параметр, сообщающий компилятору о необходимости сгенерировать код, следящий за ходом выполнения процессов.

#include ‹signal.h›

int buffer[4096];

main() {

 int offset, endof, scale, eff, gee, text;

 extern theend(), f(), g();

 signal(SIGINT, theend);

 endof = (int) theend;

 offset = (int) main; /* вычисляется количество слов в тексте программы */

 text = (endof - offset + sizeof(int) - 1) / sizeof(int);

 scale = Oxffff;

 printf("смещение до начала %d до конца %d длина текста %d\n", offset, endof, text);

 eff = (int) f;

 gee = (int) g;

 printf("f %d g %d fdiff %d gdiff %d\n", eff ,gee, eff - offset, gee - offset);

 profil(buffer, sizeof(int) * text, offset, scale);

 for (;;) {

  f(); g();

 }

}

f() {}

g() {}

theend() {

 int i;

 for (i = 0; i ‹ 4096; i++) if (buffer[i]) printf("buf[%d] = %d\n", i, buffer[i]);

 exit();

}

Рисунок 8.12. Программа, использующая системную функцию profil

смещение до начала 212 до конца 440 длина текста 57

f 416 g 428 fdiff 204 gdiff 216

buf[46] = 50

buf[48] = 8585216

buf[49] = 151

buf[51] = 12189799

buf[53] = 65

buf[54] = 10682455

buf[56] = 67

Рисунок 8.13. Пример результатов выполнения программы, использующей системную функцию profil

<p id="_9_3_4">8.3.4 Учет и статистика</p>

В момент поступления прерывания по таймеру система может выполняться в режиме ядра или задачи, а также находиться в состоянии простоя (бездействия). Состояние простоя означает, что все процессы приостановлены в ожидании наступления события. Для каждого состояния процессора ядро имеет внутренние счетчики, устанавливаемые при каждом прерывании по таймеру. Позже пользовательские процессы могут проанализировать накопленную ядром статистическую информацию.

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

Перейти на страницу:

Все книги серии Серия книг по программному обеспечению издательства prentice hall

Похожие книги