Программирование мобильных устройств на платформе .NET Compact Framework - Иво Салмре
Шрифт:
Интервал:
Закладка:
Из всех описанных стратегий включение самостоятельно разработанных средств мониторинга производительности в код приложения обеспечивает самый быстрый способ получения результатов первого порядка, представляющих наибольший интерес. Приступая к организации сбора данных для анализа показателей производительности, начинайте с оснащения кода приложения простыми средствами мониторинга и при необходимости уточняйте полученные результаты.
Получение информации об основных показателях производительности в .NET Compact FrameworkВ .NET Compact Framework версии 1.1 имеется встроенный механизм, позволяющий быстро получать "черновую" метрику работы приложений на основе управляемого кода в этой среде. Упомянутый механизм обеспечивает получение показателей производительности приложения в целом и по завершении выполнения приложения выводит соответствующий текстовый файл. В этом текстовом файле содержатся следующие данные:
• Суммарное время выполнения
• Количество объектов, размещенных в памяти в процессе выполнения кода.
• Количество операций по сборке мусора, произведенных в процессе выполнения кода.
• Количество сгенерированных исключений. (Накладные расходы, связанные с обработкой исключений, возбуждаемых часто и без крайней на то необходимости внутри циклов, могут оказаться весьма существенными )
Поскольку полученные показатели характеризуют работу программы на уровне приложения, их целесообразно использовать в тех случаях, когда вы сравниваете два различных алгоритма или настраиваете определенный алгоритм. Тестируемые алгоритмы следует выделить в собственные исполняемые файлы. Исполняемые файлы должны содержать как можно меньше лишнего кода, чтобы основная часть производимых вычислений приходилась на тестируемые алгоритмы. Исключите из кода любые другие формы или код, которые могут приводить к загрузке, JIT-компиляции и выполнению нежелательных компонентов, если таковые имеются.
Технические рекомендации относительно того, как активизировать генерацию рассматриваемых показателей времени выполнения, содержатся в статье "Developing Well Performing .NET Compact Framework Applications" ("Разработка высокопроизводительных приложений .NET Compact Framework") на Web-сайте http://msdn.microsoft.com.
На момент написания данной книги указанная статья располагалась по следующему URL-адресу:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetcomp/html/netcfperf.asp
Кроме того, в этой статье рассматриваются различные способы оценки функциональности кода на основании сравнительного анализа показателей производительности; этот материал также заслуживает прочтения.
Программа для измерения характеристик кода
Поскольку проектирование высокопроизводительных приложений — это искусство, которое должно сочетаться с исследовательским подходом, полезно иметь под рукой инструмент, с помощью которого можно было бы быстро производить необходимые измерения. Приведенный ниже пример кода вы можете использовать в своих программах для количественной оценки некоторых показателей их функционирования.
Представленный в листинге 7.1 код прост в использовании и имеет небольшие размеры, благодаря чему его включение в мобильное приложение приведет лишь к незначительному увеличению накладных расходов. Этот код предназначен для использования в качестве универсального средства тестирования производительности, при помощи которого вы сможете быстро измерять временные характеристики своих кодов. Это позволит вам быстро оценивать, сколько времени выполняется тот или иной участок разрабатываемого кода, и обнаруживать узкие места, требующие применения новых стратегий. Вы также можете использовать этот код для быстрого сравнения эффективности двух различных подходов, чтобы определить, какой из них лучше соответствует вашим запросам. Так, если для если для настройки пользовательского интерфейса и заполнения иерархического списка в элементе управления TreeView требуется три секунды, то вы можете захотеть изменить алгоритм таким образом, чтобы сначала заполнялись лишь узлы наивысшего уровня, а заполнение дочерних узлов откладывалось на более позднее время и осуществлялось лишь тогда, когда в этом возникнет действительная необходимость. Окончательное решение вы будете принимать на основании результатов соответствующих измерений и оценок качества приложения, предоставляемых конечными пользователями.
Листинг 7.1. Пример кода для измерения временных интервалов, который вы можете использовать для хронометража работы своих приложенийusing System;
internal class PerformanceSampling {
//Значение этого параметра может быть задано произвольным, но количество
//тестовых интервалов, равное 8, представляется достаточным для
// большинства случаев
const int NUMBER_SAMPLERS = 8;
static string[] m_perfSamplesNames = new string[NUMBER_SAMPLERS];
static int[] m_perfSamplesStartTicks = new int[NUMBER_SAMPLERS];
static int[] m_perfSamplesDuration = new int[NUMBER_SAMPLERS];
//Определить начальное значение счетчика тактов системных часов
//для интервала
internal static void StartSample(int sampleIndex, string sampleName) {
m_perfSamplesNames[sampleIndex] = sampleName;
m_perfSamplesStartTicks[sampleIndex] = System.Environment.TickCount;
}
//Определить конечное значение счетчика тактов системных часов
//для интервала
internal static void StopSample(int sampleIndex) {
int stopTickCount = System.Environment.TickCount;
//Счетчик тактов системных часов сбрасывается в ноль каждые 24,9 дня
//(что соответствует примерно 2 миллиардам миллисекунд).
//Эта маловероятная возможность будет принята нами во внимание
if (stopTickCount >=m_perfSamplesStartTicks[sampleIndex]) {
//Обычно будет выполняться этот код
m_perfSamplesDuration[sampleIndex] = stopTickCount - m_perfSamplesStartTicks[sampleIndex];
} else {
//Значение счетчика тактов "перешло" через ноль,
//и мы должны это учесть
m_perfSamplesDuration[sampleIndex] = stopTickCount + (int.MaxValue - m_perfSamplesStartTicks[sampleIndex]) + 1;
}
}
//Возвратить длительность тестового интервала
//(в миллисекундах)
internal static int GetSampleDuration(int sampleIndex) {
return m_perfSamplesDuration[sampleIndex];
}
//Возвращает длительность истекшего тестового
//интервала в секундах
internal static string GetSampleDurationText(int sampleIndex) {
return m_perfSamplesNames[sampleIndex] + ": " +
System.Convert.ToString((m_perfSamplesDuration[sampleIndex] /(double) 1000.0)) +
" секунд.";
}
}
HA ЗАМЕТКУВ документации по .NET Compact Framework утверждается, что интервал значений свойства .TickCount не может быть меньше 500 мс (0,5 секунды). Я обнаружил, что на практике достигается несколько лучшее разрешение (менее 100 мс, или 0,1 секунды), чем указанное. Вам придется немного поэкспериментировать самостоятельно. Если окажется, что вам необходим счетчик с более высоким разрешением, можете видоизменить приведенный выше код, включив в него системные вызовы операционной системы, управляющей собственным кодом, для получения доступа к низкоуровневым системным счетчикам. В большинстве случае возможностей приведенного выше кода вам должно быть вполне достаточно, а в силу своей простоты он оказывается удобным для использования в тех случаях, когда измерения требуется выполнить быстро.
Листинг 7.2. Тестовая программа, демонстрирующая использование приведенного выше кода для измерения временных интерваловprivate void button1_Click(object sender, System.EventArgs e) {
const int TEST_SAMPLE_INDEX = 2; //Выберите любое действительное
//значение индекса
//Начать измерение
PerformanceSampling.StartSample(TEST_SAMPLE_INDEX, "TestSample");
//Отобразить окно сообщений
System.Windows.Forms.MessageBox.Show("Для прекращения измерения щелкните на кнопке OK");
//Прекратить измерение
PerformanceSampling.StopSample(TEST_SAMPLE_INDEX);
//Отобразить результаты
System.Windows.Forms.MessageBox.Show(PerformanceSampling.GetSampleDurationText(TEST_SAMPLE_INDEX));
}
Советы относительно повышения надежности результатов измерений1. Вы можете пользоваться эмпирическим правилом, в соответствии с которым чем больше длительность события, которую вы измеряете, тем меньше относительная ошибка. Поэтому, если вы сравниваете два алгоритма, для выполнения которых требуется примерно 0,5 секунды, лучше выполнить каждый из них по 10 раз и разделить полученные результаты на 10.
2. Повторяйте каждый эксперимент несколько раз, убеждаясь в том, что получаемые результаты оказываются в достаточной степени близкими друг к другу.