Почему в моем приложении WPF GetMessageW заняло значительное использование процессора? - PullRequest
10 голосов
/ 08 ноября 2010

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

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

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

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

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

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

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

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

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

ОБНОВЛЕНИЕ:В ответ на некоторые обсуждения ниже, есть еще одно представление от ANTS - это лучше иллюстрирует путаницу, которую я испытываю (это с представлением ANTS в режиме «CPU time»).Я поспешно подверг цензуре части нашего кода, но ни одна из функций, связанных с системой:

alt text

Спасибо за внимание!

Ответы [ 4 ]

3 голосов
/ 08 ноября 2010

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

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

1 голос
/ 08 ноября 2010

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

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

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

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

alt text

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

alt text

0 голосов
/ 16 декабря 2010

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

Я работаю на WinXP box - инфраструктура WPF более интегрирована в Vista и Win7, чем в XP. Отчасти это может быть связано с тем, что WPF работает «поверх» рабочего стола XP, а не внутри него.

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

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

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

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

0 голосов
/ 08 ноября 2010

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

Изменить

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

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

...