DeepEdit!

Программирование баз данных на Oracle, техническая документация, литература, статьи и публикации

  • Увеличить размер шрифта
  • Размер шрифта по умолчанию
  • Уменьшить размер шрифта

О важности тестирования системы


Инструмент, подобный strace, позволяет проверить предположения о точности измерения времени ядром Oracle для конкретной системы. У нас есть один файл трассировки, сформированный версией Oracle 9.2.0.1.0 для Compaq OSF1, в котором c имеет разрешение 3333.3 мкс, e - разрешение 1000 мкс, а ela - 10000 мкс. Эти данные вызывают ре­зонный вопрос о том, действительно ли значения e и ela для данной платформы получены от одного системного вызова gettimeofday. (Если бы это было так, т. е. значения e и ela для данной платформы были бы результатами одного системного вызова, почему бы они могли иметь очевидно различную точность измерения?) При наличии трассировки системного вызова на этот вопрос было бы очень просто ответить. В про­тивном случае нам остается только гадать.
Определение ошибки квантования
Ошибка квантования обозначается буквой и определяется как раз­ность между реальной продолжительностью события ea и его измерен­ной продолжительностью em. То есть
Вернемся к примеру 7.1, точнее, к его отображению на шкале времени на рис. 7.5. На этом рисунке каждое деление соответствует такту ин­тервального таймера, подобного таймеру gettimeofday. В момент нача­ла dosomething таймер имел значение t0 = 1492, а в момент завершения dosomething - t1 = 1498. То есть измеренная продолжительность вызо­ва dosomething равна em = t1 -10 = 6. Однако если измерить длину от­резка, соответствующего продолжительности ea на рисунке, то окажется, что реальная длительность исполнения something (ea) равна 5,875 такта. Точное значение длительности можно получить, измерив линейкой высоту отрезка ea на рисунке, а вот приложение не может получить точное значение ea, имея в своем распоряженинии только интервальный таймер с указанным размером такта. Ошибка квантова­ния составляет = em - ea = 0,125 такта или около 1,7% реальной дли­тельности (5,875 тактов).
Рис. 7.5. Интервальный таймер с удовлетворительной точностью измеряет длительности событий, охватывающих множество тактов его часов
Теперь рассмотрим случай, в котором длительность исполнения do_so-mething близка к разрешению таймера, как это показано на рис. 7.6. В левой части рисунка длительность dosomething покрывает всего одно деление шкалы, так что его измеренная продолжительность em=1. Од­нако фактическая продолжительность события составляет всего ea=0,25 (это значение можно проверить, измерив длину отрезка на ри­сунке). В данном случае ошибка квантования вычисляется как = 0,75, т. е. составляет целых 300% реальной длительности события (0,25 так­та). В правой части рисунка выполнение вызова dosomething не захва­тывает ни одного такта системных часов, и его измеренная продолжи­тельность em = 0, в то время как реальная длительность ea = 0,9375. Те­перь ошибка квантования = -0,9375 и составляет -100% реальной длительности события (0,9375 такта).
Упрощенно ошибку квантования можно описать следующим образом:
Точность любого измерения, выполненного интервальным таймером, не превышает единицы его разрешающей способности.
Если формулировать строже, то разность двух отсчетов цифровых ча­сов равна сумме фактической продолжительности и ошибки квантова­ния, точное значение которой определить невозможно, известен лишь диапазон таких значений: приблизительно от -1 такта до +1 такта сис­темных часов. Если обозначить разрешение некоторого таймера пе­ременной rx, то получится следующее соотношение:
Ошибка квантования E, свойственная любому дискретному (цифрово­му) измерению, - это равномерно распределенная случайная перемен­ная (см. главу 11) с диапазоном значений -rx < < rx, где rx - это раз­решающая способность интервального таймера.
Любое значение фактической продолжительности, выводимое ядром Oracle (или каким-то другим программным обеспечением), следует воспринимать с учетом точности измерений. Например, если в файле трассировки Oracle8i встречается значение e=4, то не стоит думать, что реальная длительность какого-то события равнялась 4 сантисекун-дам. На самом деле такое значение показывает, что если разрешение таймера составляет не более 1 сантисекунды, то реальная продолжи­тельность события находится в диапазоне от 3 до 5 сантисекунд. И это наиболее точная из доступных вам оценок.
Если собранные значения малы, то такая погрешность может привес­ти к курьезным результатам. Например, нельзя даже будет корректно сравнить длительности событий, измеренные длительности которых приблизительно равны. Несколько таких курьезных ситуаций изобра­жено на рис. 7.7. Представим, что таймер тикает с интервалом в одну сантисекунду. Это имитирует работу Oracle8i, где значащие разряды, следующие за сотыми долями секунды, усекаются. На рисунке видно, что фактическая продолжительность события превышает фактиче­скую продолжительность события B, но их измеренные продолжи­тельности находятся в обратном отношении. Событие заняло больше времени, чем D, при этом имеет большую измеренную продолжи­тельность. Обобщая, можно сказать, что любое событие с измеренной продолжительностью + 1 может иметь фактическую длительность, которая больше, равна или даже меньше, чем у другого события с из­меренной продолжительностью n. И вы не можете знать, какое отно­шение имеет место в данном случае.
Интервальный таймер может выполнять измерения только с точно­стью до ±1 такта системных часов, но на практике это ограничение не уменьшает полезность применения таких таймеров. При больших объемах выборок положительные и отрицательные ошибки квантова­ния постепенно компенсируют друг друга. Например, сумма ошибок квантования для случая, изображенного на рис. 7.6, равна:
E1 + E2 = 0,75 + (-0,9375) = 0,1875
В отличие от значительных относительных величин отдельных оши­бок их сумма оказывается гораздо меньше и составляет 16% от суммы реальных длительностей событий. Проанализировав в hotsos.com не­сколько сотен файлов трассировки SQL, полученных от сотен различ­ных систем Oracle, мы выявили тенденцию взаимного погашения по­ложительной и отрицательной ошибок квантования в файлах в не­сколько сотен строк. В большинстве случаев величина суммарной ошибки не выходит за пределы ±10% общего времени отклика, изме­ренного в файле трассировки.
Сложности измерения процессорного времени
Возможно, вы обратили внимание на то, что системные вызовы gettim­eofday дают существенно большую точность, чем getrusage. Несмотря на то, что псевдокод в примере 7.3 создает ощущение, что gettimeofday и getrusage делают практически одно и то же, в реальности эти две функции работают совершенно по-разному. И в результате имеют аб­солютно разную точность.
Как работает gettimeofday
Разобраться, как работает gettimeofday, гораздо легче, чем сделать это для getrusage. Будем рассматривать в качестве примера Linux на про­цессоре Intel Pentium. Как я уже говорил, процессор Intel Pentium имеет аппаратный счетчик временных меток TSC, который обновляет­ся с каждым тактом аппаратных часов. Например, процессор с часто­той 1 ГГц обновляет счетчик приблизительно миллиард раз в секунду [Bovet and Cesati (2001) 139-141]. Подсчитывая количество тактов, зарегистрированных счетчиком с тех пор, когда пользователь устано­вил время командой date, ядро Linux может определить, сколько так­тов прошло с момента начала эпохи Unix. Возвращаемый gettimeofday результат - это полученное число, усеченное до микросекунд (для обеспечения соответствия функции gettimeofday стандарту POSIX).
Как работает getrusage
Операционная система может учитывать процессорное время, израс­ходованное процессом в пользовательском и привилегированном ре­жиме, двумя способами:
Опрос (Polling)
Операционная система может содержать специальный код, позво­ляющий каждому выполняющемуся процессу через фиксированные интервалы времени обновлять собственную таблицу rusage. На каж­дом интервале каждый работающий процесс может обновлять соб­ственную статистику расходования ресурсов процессора, считая, что он использовал процессор в течение всего интервала в том режи­ме, в каком процесс находится в текущий момент.1
Событийно обусловленные измерения (Event-based instrumentation)
Операционная система может содержать специальный код, кото­рый при каждом переходе процесса в пользовательский или приви­легированный режим осуществляет вызов таймера высокой точно­сти. При каждом выходе процесса из такого состояния ОС может повторно вызывать таймер и выводить величину (в микросекундах) разности между двумя вызовами в структуру rusage процесса.
В большинстве операционных систем (по крайней мере, по умолчанию) применяется опрос. Так, Linux обновляет несколько атрибутов для ка­ждого процесса, в том числе использованное до указанного момента процессорное время, при каждом прерывании по таймеру [Bovet and Cesati (2001) 144-145]. Некоторые операционные системы поддержи­вают событийно обусловленные измерения. Например, такая возмож­ность имеется в Sun Solaris под названием «учет микросостояний» (microstate accounting) [Cockroft (1998)].
При учете микросостояний ошибка квантования ограничена одной единицей разрешения таймера на каждое переключение состояния. В случае применения таймера с высоким разрешением (подобного gettimeofday) общая ошибка квантования для статистики использова­ния процессора, полученная в результате учета микросостояний, ока­зывается совсем небольшой. Но повышение точности достигается за счет увеличения эффекта влияния измерителя. Однако, как вы сейчас увидите, в случае применения опроса ошибка квантования может быть значительно больше.
Независимо от того, каким способом получена информация о расходо­вании ресурсов, операционная система предоставляет эту информа­цию любому процессу, которому она необходима, посредством систем­ного вызова, подобного getrusage. Стандарт POSIX требует, чтобы в ка­честве единицы измерения в функции getrusage выступали микросе­кунды, но для систем, получающих данные rusage путем опроса, реальное разрешение получаемых данных зависит от частоты преры­ваний по таймеру.
В большинстве систем частота составляет 100 прерываний в секунду или 1 прерывание в сантисекунду (в текстах операционных систем значения часто выражены в миллисекундах: 1 сантисекунда = 10 мил­лисекунд = 0,010 секунды). Частота прерываний по таймеру во мно­гих системах устанавливается параметром, но большинство систем­ных администраторов оставляет ее равной 100 прерываниям в секун­ду. Если попросить систему обслуживать прерывания чаще 100 раз в секунду, то точность измерения времени будет выше, но при этом пострадает производительность. Даже если обслуживать прерывания всего в десять раз чаще, накладные расходы на работу планировщика в привилегированном режиме возрастут в десять раз. Такое решение нельзя считать разумным компромиссом.
Если операционная система соответствует стандарту POSIX, то опре­делить разрешение ее планировщика поможет следующая программа на Perl [Chiesa (1996)]:
Если системные часы имеют разрешение в одну сантисекунду, то ge-trusage может возвращать значение в микросекундах, но такие значе­ния никогда не будут содержать корректную информацию в разрядах младше, чем сотые доли секунды.
Причина, по которой я вам все это объясняю, заключается в том, что ошибка квантования статистики c для Oracle в корне отличается от ошибки квантования статистик e и ela. Вернемся к утверждению:
Точность любого измерения, выполненного интервальным таймером, не превышает единицы его разрешающей способности.
Проблема статистики c заключается в том, что величина, возвращае­мая функцией getrusage, - это на самом деле не продолжительность. То есть «продолжительность» использования процессора, возвращае­мая getrusage, не вычисляется как разность пары измерений интер­вального таймера.
В системах, где ведется учет микросостояний, объем использова­ния процессора вычисляется как сумма очень большого количества коротких временных интервалов.
В системах, получающих информацию rusage путем опроса, объем использования процессора - это приблизительная оценка продол­жительности, полученная в процессе опроса.
Получается, что в любом случае ошибка квантования, присущая ста­тистике c, может быть гораздо более серьезной, чем просто один такт системных часов. Проблема актуальна даже в системах, применяю­щих учет микросостояний. В системах, которые это не делают, все об­стоит еще хуже.
На рис. 7.8 изображена типичная ситуация при организации опроса, в которой ошибки определения времени занятости процессора в поль­зовательском режиме приводят к учету лишнего времени при вычисле­нии времени отклика вызова базы данных. Диаграмма последователь­ности состояний на этом рисунке приводит время занятости процессора в пользовательском режиме и время системного вызова, потребленные вызовом базы данных. На оси ЦПУ отмечены прерывания системного таймера с интервалом в 1 сантисекунду. Размер рисунка не позволяет отобразить на оси «Время, потраченное вне ЦПУ» 10 000 тактов, кото­рые проходят между каждой парой тактов на оси ЦПУ.
Можно предположить, что в результате операций, изображенных на рис. 7.8, ядро Oracle9i сформирует данные трассировки, подобные при­веденным в примере 7.5. Я вычислил ожидаемые значения статистик e и ela, измеряя длины отрезков на рисунке. Благодаря высокой точно­сти таймера gettimeofday, с помощью которого я выполнял измерения, ошибка квантования таких измерений e и ela пренебрежимо мала.
Пример 7.5. Временные статистики Oracle9i, которые могли бы быть получены в результате событий, изображенных на рис. 7.8
Реально затраченное вызовом базы данных процессорное время со­ставляет 2,5 сантисекунды. Это значение я получил, физически изме­рив длины соответствующих отрезков на рис. 7.8. Однако getrusage по­лучает свои данные об использовании процессора из структуры расхо­дования ресурсов процессом, обновляемой в результате опроса по пре­рываниям таймера. При каждом прерывании планировщик процессов операционной системы добавляет одну полную сантисекунду (10 000 мкс) процессорного времени любому процессу, исполняемому в данный момент времени. Соответственно, getrusage сообщит о том, что вызов базы данных на рис. 7.8 занял шесть полных сантисекунд времени процессора. Проверить результат очень просто - посмотрите на рис. 7.8 и сосчитайте количество тактов, пришедшихся на моменты использования процессора.
На рисунке все кажется разумным, но обратите внимание на неучтен­ное время:
Если значение неучтенного времени меньше нуля, значит, данные трассировки содержат отрицательную величину «упущенного време­ни». Другими словами, вызову базы данных приписаны лишние 39 375 мкс. Это число выглядит настораживающе большим, но не за­бывайте о том, что на самом деле это всего около 4 сантисекунд. Реаль­но же вызов базы данных затратил в пользовательском режиме всего 25 000 мкс времени процессора (опять-таки, это значение я получил мошеннически, измерив длины отрезков на рис. 7.8).

 









jAntivirus