Программирование на Visual C++. Архив рассылки - Алекс Jenter
Шрифт:
Интервал:
Закладка:
В заключение отмечу, что я нигде не использовал тот факт, что виды порождаются от CFormView. Поэтому описанные мною способы годятся для любых других видов (например, порождённых от CScrollView или CListView).
Alexander Shargin В ПОИСКАХ ИСТИНЫQ. У меня вопрос для гуру. В конференциях от пару раз возникал, но как-то так тихо и кончался. То ли это очевидная истина, то ли никто не знает (чему я не верю). Итак вопрос: как в программу на правую кнопку подцепить меню, такое же как в Експлорере? Как туда напихать свои элементы? Второй второй вопрос отпадает, если можно выцепить именно меню, а не какую-то системную функцию, которая выводит окно меню, а тебе с этим сприходится смиряться, как с фактом бытия этого экранного элемента…
Serg LoginovЭто все на сегодня. Пока!
Алекс Jenter [email protected] Красноярск, 2000.Программирование на Visual C++
Выпуск №25 от 26 ноября 2000 г.
Приветствую вас, уважаемые подписчики!
СТАТЬЯ Профилирование : анализ и оптимизацияПрофилирование – это очень мощный инструмент анализа поведения вашей программы, позволяющий во время ее выполнения выявить "узкие места", где происходит падение производительности. С помощью профилирования можно получить статистику вызова функций, чтобы в дальнейшем использовать эту информацию при оптимизации кода. Ведь каждому понятно, что нет смысла оптимизировать функцию, вызывающуюся всего пару раз. При использовании MFC это тем более актуально, т.к. многие вызовы не всегда очевидны для программиста.
Еще одна причина использования профилирования – это контроль за качеством тестов. Такой контроль предоставляет информацию о том, осуществляет ли данный тест вызов и обработку результатов выполнения всех без исключения подпрограмм, и какие строки кода при этом выполняются.
Профилирование по сути совершенно НЕ аналогично отладке, и используется с другой целью: не для отлова ошибок, а для улучшения работы приложения – в подавляющем большинстве случаев, это равносильно "для увеличения скорости работы".
Итак, профилирование используется для того, чтобы определить:
1. Оптимален ли использованный алгоритм (по времени);
2. Слишком большое (или слишком малое) количество вызовов подпрограммы;
3. Покрывается ли участок кода тестирующими процедурами.
Приведу пример из жизни: в программе, осуществляющей доступ к данным из файла MS Access, наблюдалось катастрофичное падение производительности при превышении объема данных определенной величины, причем относительно небольшой (порядка 500 записей). Применение профилирования позволило мгновенно выяснить, что подпрограмма, извлекающая данные из базы, совершенно здесь не при чем, а всему виной подпрограмма, заносящая данные в таблицу на экране. После внесения соответствующих изменений, все отлично (т.е. БЫСТРО) заработало, причем скорость программы при просмотре записей практически перестала зависеть от объема данных.
Разделяют два вида профилирования: по функциям и по строкам кода.
Профилирование по функциям полезно для выявления неэффективного кода. Также оно быстрее, чем профилирование по строкам, т.к. приходится собирать меньше информации. Включает в себя следующие измерения:
• суммарный объем времени, в течение которого выполнялась функция + количество вызовов этой функции (function timing),
• только количество вызовов функции (function counting),
• список ни разу не вызывавшихся функций (function coverage),
• запись содержимого стека при каждом вызове функции (function attribution).
Профилирование по строкам используется для проверки алгоритмов, т.к. позволяет посмотреть, сколько раз была выполнена каждая строчка, а также выявить строки, не выполнившиеся вообще ни разу. Здесь есть только два варианта: подсчет строк (line counting) – т.е. сколько раз данная строка была выполнена; и покрытие строк (line coverage) – показывает те строки, которые выполнялись хотя бы раз.
Перейдем к практике. Если у вас установлен Visual C++ Professional или Enterprise Edition, то профилировщик у вас есть, он встроен в IDE. Осталось только научиться им пользоваться. Предугадывая поток писем, замечу, что существует довольно большой выбор всяческих профилировщиков от сторонних фирм, возможности которых иногда действительно впечатляют. Но в данной статье я кратко рассмотрю возможности профилирования, встроенные в Visual C++.
Прежде всего необходимо установить опции проекта для включения профилирования (т.е. генерации профилировочной информации). Это делается через Project Settings|Link|Enable Profiling.
Дальше выберите Build|Profile, и появится диалог "Profile", где можно выбрать любой тип профилирования, плюс еще есть возможность как следует это все настроить с помощью Custom Options (см. параметры команды PREP). Примечательна также опция Merge – позволяет совместить текущие результаты с предыдущими для наглядного сравнения. После нажатия на "OK" запускается ваша программа – дальше вы производите те действия, которые вам необходимо проверить. По завершении работы вашего приложения, профилировочная информация выводится в Profile Output Window, где вы ее анализируете… и делаете выводы.
И напоследок, несколько советов.
1. Не стоит профилировать все приложение целиком, лучше сконцентрироваться на каких-то отдельных частях, представляющих наибольший интерес. (См. параметры /EXC и /INC). Есть много частей, которые просто нет смысла профилировать – такие, как пользовательский интерфейс, например.
2. Замеры не всегда будут точными, поэтому имеет смысл брать среднее значение от нескольких проходов. Собирать статистику за несколько проходов можно с помощью опции Merge.
3. Когда вы профилируете, постарайтесь, чтобы количество запущенных процессов в системе было минимальным.
4. Лучше отсоединиться от локальной сети или интернета, чтобы ОС не приходилось принимать входящие пакеты.
5. Следите за количеством вызовов. Например, у вас в алгоритме есть итерация на тысячу повторений – проследите, чтобы функции, которыми он пользуется, вызывались соответствущее число раз.
6. Время, в течение которого выполняется функция, включает также и время, в течение которого выполнялись все функции, вызванные из данной.
Заинтересовавшимся данной темой предлагаю следующие статьи в MSDN:
• Performance Tuning
• Using Profile, PREP and PLIST
• Profiling from the Development Environment
ВОПРОС-ОТВЕТQ. У меня вопрос для гуру. В конференциях от пару раз возникал, но как-то так тихо и кончался. То ли это очевидная истина, то ли никто не знает (чему я не верю). Итак вопрос: как в программу на правую кнопку подцепить меню, такое же как в Експлорере? Как туда напихать свои элементы? Второй второй вопрос отпадает, если можно выцепить именно меню, а не какую-то системную функцию, которая выводит окно меню, а тебе с этим сприходится смиряться, как с фактом бытия этого экранного элемента…
Serg LoginovA1 Контекстное (правокнопочное) меню создать довольно просто:
1. Добавляем в графическом редакторе новое пустое меню.
2. Для крайнего слева элемента верхнего уровня вводим какое-нить имя и в полученное раскрывающееся меню добавляем команды.
3. Вставляем обработчик сообщения WM_CONTEXTMENU в класс "вид" или в класс другого окна, получающего сообщения от кнопок мыши, ну, например, в CMyDialog. Обработчик этот программируем так:
CMyDialog::OnContextMenu(CWnd* pWnd, CPoint point) {
CMenu menu;
menu.LoadMenu(IDR_MYMENU);
menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
}
Вот и все. TrackPopupMenu и занимается выводом контекстного меню на экран. Правда, объект класса CMenu лучше сделать мембером класса, тогда в любой функции можно будет удалять, добавлять, запрещать etc. элементы меню. Конечно, в этом случае m_Menu.LoadMenu(IDR_MYMENU); надо написать в OnInitDialog. Заметте, OnContextMenu получает координаты курсора, т.е. можем для разных областей окна элементарно выводить разные меню, просто проверяя координаты.
Sergey PochechuevA2 В Windows все файлы и папки входят в иерархию объектов оболочки. В неё также входят и объекты, не имеющие отношение к файловой системе: корзина, рабочий стол и т. п. Windows Explorer является по сути программой для просмотра этой иерархии объектов.
Каждый объект оболочки обязан реализовывать COM-интерфейс IShellFolder. Многие объекты реализуют и ряд других интерфейсов. Так, IExtractIcon отвечает за иконку объекта, а IContextMenu – за его контекстное меню. Эксплорер использует эти (и другие) интерфейсы, чтобы корректно отображать элементы иерархии объектов и позволять пользователю манипулировать ими. Мы также можем воспользоваться этими интерфейсами.
Итак, нам требуется функция, которая выводила бы контекстное меню для заданного файла (каталога), который передавался бы ей в качестве параметра. Эта функция должна выполнить следующие действия: