Чтение онлайн

ЖАНРЫ

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

Во втором тесте полученное изображение

Cnt
раз выводится на экран. Если бы оно выводилось всегда в одном и том же месте, пользователь не видел бы процесс вывода на экран, т.к. каждый следующий раз картинка рисовалась бы точно в том же месте, что и в предыдущий, и общее изображение не менялось бы. Чтобы этого не происходило, изображение выводится со случайным смещением относительно базовых координат, и пользователь может наблюдать за процессом. Кроме того, координаты определяются также параметром XOfs — это сделано для того, чтобы при тестировании DDB- и DIB-изображений рисунки выводились в разных частях окна и не накладывались друг на друга.

На некоторых компьютерах в этом тесте с DDB-изображением

наблюдается интересный эффект: время, измеренное программой, заметно меньше, чем время, когда картинка меняется на экране (например, пользователь ясно видит, что тест выполняется в течение примерно трех секунд, в то время как программа дает значение около одной секунды). Это связано со способностью некоторых видеокарт буферизовать переданные им команды и выполнять их асинхронно, т.е. вызов функции завершается очень быстро, программа продолжает работать дальше, а видеокарта параллельно ей выполняет команду. Если вы столкнетесь с такой ситуацией, можете провести небольшой эксперимент: вставить вызов функции Beep сразу после окончания второго теста. Вы услышите звуковой сигнал раньше, чем изображение закончит меняться.

Третий тест самый простой:

Cnt
раз значение свойства ScanLine присваивается переменной
P
. Так как значение
P
потом нигде не используется, компилятор выдает соответствующую подсказку, но в данном случае ее можно игнорировать.

Таким образом, метод

DoTest
нужно вызвать два раза: для DDB-изображения и для DIB это делает обработчик нажатия кнопки
BtnStart
(листинг 1.41).

Листинг 1.41. Обработчик нажатия кнопки
BtnStart

procedure TForm1.BtnStartClick(Sender: TObject);

var

 IterCnt, RandomStart: Integer;

begin

 IterCnt := StrToInt(EditIter.Text);

 GridResults.Cells[1, 1] := '';

 GridResults.Cells[1, 2] := '';

 GridResults.Cells[1, 3] := '';

 GridResults.Cells[2, 1] := '';

 GridResults.Cells[2, 2] := '';

 GridResults.Cells[2, 3] := '';

 // Чтобы новый текст ячеек отобразился в GridResults,

 // нужно, чтобы было извлечено их очереди и обработано

 // сообщение WM_PAINT. Чтобы сделать это немедленно,

 // вызываем Application.ProcessMessages.

 Application.ProcessMessages;

 Random.Start := Random(MaxInt);

 Screen.Cursor := crHourGlass;

 // Точное измерение времени выполнения кода в Windows

 // невозможно, потому что это многозадачная система, и

 // часть измеренного времени может быть потрачена на

 // выполнение кода других процессов. Чтобы максимально

 // уменьшить погрешность измерения, нужно установить

 // наивысший приоритет процессу и его главной нити -

 // тогда вероятность переключения процессора на

 // выполнение другой задачи будет минимальным. Столь

 // высокий приоритет приводит к тому, что во время

 // выполнения теста система
перестаёт реагировать на

 // перемещение мыши. Поэтому необходимо использовать блок

 // try/finally, чтобы даже при возникновении исключения

 // приоритет процесса и нити был снижен до нормального

 // уровня.

 SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_TIME_CRITICAL);

 SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS);

 try

// В тестах активно используются псевдослучайные числа.

// Чтобы сравнение было корректно, нужно, чтобы

// последовательности чисел в экспериментах с DIB и DDB

// были одинаковыми. Каждое следующее псевдослучайное

// число генерируется на основе значения глобальной

// переменной модуля System RandSeed. Значение RandSeed

// при этом обновляется по определенному закону. Таким

// образом, если установить определенное значение

// RandSeed, то последовательность псевдослучайных чисел

// будет строго детерминирована. Это свойство генератора

// случайных чисел используется, чтобы в обоих

// экспериментах были одинаковые последовательности.

RandSeed := RandomStart;

DoTest(IterCnt, 200, 1, pfDevice);

RandSeed := RandomStart;

DoTest(IterCnt, 450, 2, pf24bit);

 finally

Screen.Cursor := crDefault;

SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_NORMAL);

SetPriorityClass(GetCurrentProcess, NORMAL_PRIORITY_CLASS);

 end;

end;

Все три теста используют случайные числа. Чтобы условия были одинаковыми, нужно обеспечить идентичность последовательностей случайных чисел при тестировании DDB- и DIB-изображений. К счастью, этою легко добиться, установив перед тестированием одинаковые значения переменной

RandSeed
модуля
System
, которая и определяет последующее случайное число. Начальное значение
RandSeed
также выбирается случайным образом, а т.к. в обработчике события
OnCreate
формы есть вызов
Randomize
, при каждом запуске будет сгенерирована новая последовательность случайных чисел. Это одна из причин того, что результаты тестов будут меняться от запуска к запуску.

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

Поделиться с друзьями: