Почему GetMessageW будет использовать массовое использование процессора в моем приложении WPF?

У меня есть серьезный головной уборщик на руках. Я изучаю проблемы производительности с компонентом WPF в нашем приложении.

Наше приложение .net очень велико и почти полностью в виде окон. В рамках новой инициативы мы переписали один из наших основных компонентов с богатым WPF ui. Существует много взаимодействий WinForms ↔ WPF с этой штукой, чтобы склеить их вместе, и я подозреваю, что это может быть каким-то образом связано с тем, что я вижу.

Когда я просматриваю медленную операцию в профилировщике ANTS, я вижу много активности внутри функции UnsafeNativeMethods.IntGetMessageW. ANTS сообщает о том, что активность процессора идет именно так, как это происходит со всей нашей бизнес-логикой и wpf-рендерингом. Отсутствует управляемый код в нижней части этой функции, которая использует циклы, поэтому независимо от того, что делает IntGetMessageW, это то, что мне нужно.

Я не очень хорошо разбираюсь в программировании win32, но я знаю основы цикла сообщений в этом контексте. Ничто из того, что я здесь вижу, - это все, что мы делаем вручную - ни в коем случае в нашем коде мы не взаимодействуем напрямую либо с самим базовым мессалогом, либо с любым более сложным материалом, доступ к которому можно получить в диспетчере WPF.

Здесь наш компонент WPF написан наследующим от Window (т.е. не просто элементом управления /usercontrol ), и мы показываем его с помощью ShowDialog из нашей логики более высокого уровня, которая использовалась для вызова ShowDialog в старой версии WinForms этого компонент. Есть некоторые элементы управления WindowsFormsIntegrationHost, которые мы использовали внутри компонента WPF, чтобы сохранить совместимость с некоторыми из наших существующих фрагментов, которые нельзя было переписать в WPF.

Я исследовал это в течение нескольких дней, но так и не смог найти много нового. Я продолжаю находить смутно связанные публикации, которые говорят о входных сообщениях (мышь и клавиатура), но я не знаю, что я могу сделать, чтобы проверить это; Я уже пытался разбить код, чтобы удалить каждую операцию мыши/клавиатуры, которую я мог бы сделать.

Мне нелегко добраться в первую очередь из-за того, что эта строка кода полностью изолирована (а не родитель или ребенок из всего, что я могу указать, как фактически исходящий из нашего кода), и полностью непрозрачна в отношении того, что она делает.

Вот изображение графика вызовов ANTS функции ShowDialog, показывающего путь к вызовам: alt text

Я полностью понимаю, что это может быть что-то, что нужно сделать только как часть WPF (хотя другие компоненты, написанные в WPF, не отображают это поведение), или что это просто очень странная ошибка в профилировании ANTS, но в этот момент мне нужно проверить это так или иначе. Если кто-нибудь может сказать мне, что здесь происходит или может быть здесь, или указать мне каким-то образом, я смогу понять это сам, я направлю все виды хорошей кармы на ваш путь.

UPDATE: В ответ на некоторое обсуждение ниже, вот еще один взгляд от ANTS - это лучше иллюстрирует путаницу, которую я испытываю (это с представлением ANTS в режиме "CPU time" ). Я спешно подвергал цензуре части нашего кода, но ни одна из связанных с системой функций:

alt text

Спасибо, что посмотрели!

Ответ 1

Я нашел это при поиске информации по той же проблеме. Я добавлю то, что знаю, и посмотрю, поможет ли это:

Я запускаюсь в окне WinXP - среда WPF более интегрирована в Vista и Win7, чем в XP. Некоторые из них могут быть связаны с тем, как WPF работает "сверху" рабочего стола XP, а не внутри него.

Я запускаю собственное собственное приложение WPF - без WinForms или другого кода.

Я столкнулся с этим, пытаясь определить, почему просто прокрутка окна будет потреблять 100% процессор и заикаться, делая это.

Запуск профилировщика производительности AQtime, я вижу, что IntGetMessageW занимает большую часть этого 100% использования ЦП. Это не связано с тем, что IntGetMessageW ожидает сообщения, но что-то действительно выполняет функция.

Единственное, что я еще не изучил, это то, что, возможно, IntGetMessageW никогда не был быстрым методом, и, возможно, WPF просто злоупотребляет им. Возможно, привязки данных в WPF используют встроенный насос сообщений Win32 для обновления свойств зависимостей в WPF. Если это так, возможно, что в моем окне слишком много привязок.

Ответ 2

Да, это нормально. Любое приложение GUI всегда выполняет GetMessageW(), ожидая, что Windows отправит ему сообщение. На самом деле это не происходит сжиганием циклов процессора, просто блокируется на внутреннем объекте синхронизации до тех пор, пока не будет сообщено какое-либо событие UI.

Это, конечно, затрудняет профилирование приложений пользовательского интерфейса, вам действительно нужны модульные тесты, которые проверяют подкомпоненты вашего приложения.

Ответ 3

При профилировании приложения вам нужно различать время, затраченное на использование метода и циклов процессора. Многие инструменты профилирования показывают вам общее время, затрачиваемое на метод, который в случае somthing like GetMessageW будет довольно высоким. Вся деятельность основного потока приложения GUI появится в этом методе. Это не обязательно проблема, однако... это может быть просто основной насос сообщений, ожидающий объектов синхронизации и фактически не потребляющий циклы.

Я бы предложил начать с использования функции пробоотбора в профилировщике ANTS, чтобы идентифицировать методы, которые чаще всего вызываются, и сопоставлять их с методами, которые потребляют большинство циклов процессора. вы сделали это, вы сами решаете, где инструмент для вашего приложения, чтобы погрузиться дальше, и получите представление о том, как выглядят графики вызовов для мест, которые наиболее интенсивно работают с процессором.

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

Я предлагаю вам также провести некоторое время изучение возможностей профилировщика. Профилировщики могут быть сложными и запутанными инструментами, пока вы не поймете, что именно они пытаются показать вам. Связанный tutoral от RedGate должен стать хорошим местом для начала, если вы еще этого не сделали. Например, представление временной шкалы на самом деле может быть хорошим местом, чтобы начать видеть, где происходит высокая активность процессора, и ограничивая анализ этими сегментами исполняемого кода.

alt text

Call Call - еще один полезный инструмент в ANTS, так как он помогает вам развернуть области наиболее дорогого кода. Ключ должен убедиться, что вы смотрите на общую стоимость, а не только на общее время.

alt text

Ответ 4

Похоже, что ваш насос сообщений сильно накачивается. Может быть интересно посмотреть, какое сообщение заполняется в очереди сообщений. Можете ли вы использовать Spy ++ в своем окне, чтобы узнать, что происходит?

Edit

Я неправильно понял проблему.

Ханс Пассант прав, ваша программа просто ждет GetMessage для обработки какого-либо события.