Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Потеря производительности, при рисовании в окне 
:(
    Опции темы
voov
Дата 10.6.2009, 13:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Патамушта мы пилоты
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 29.11.2007

Репутация: 8
Всего: 8



У меня есть дллка, в которой класс, рисующий график.
Ранее это был класс, унаследованный от CObject. Ему передавался контекст утройства, на котором он и рисовал график.
Теперь это класс, унаследованный от окна. Отрисовка та же, но в своей клиентской области.

Эту библиотеку использую в МДИ приложении в одном из видов.
Ранее, при необходимости перерисовать вид, в класс графика передавался указатель на CDC. 
Теперь в вид добавлено дочернее окно, которому просто сообщается, что нужно выполнить перерисовку.

Код отрисовки графика тот же, но новый вариант (с окном) занимает процесорного времени примерно в 2 раза больше. 

Почему так происходит? Неужели столько ресурсов отнимает обрабтка сообщений еще одного окна?
PM MAIL   Вверх
voov
Дата 15.6.2009, 13:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Патамушта мы пилоты
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 29.11.2007

Репутация: 8
Всего: 8



Если непонятно объяснил или нужна еще какаято информация, спрашивайте. 
Никак не могу понять почему так происходит...
PM MAIL   Вверх
Earnest
Дата 16.6.2009, 08:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Цитата(voov @  10.6.2009,  14:55 Найти цитируемый пост)
Почему так происходит? Неужели столько ресурсов отнимает обрабтка сообщений еще одного окна? 

Вряди ли, если конечно, ты там не наворотил что-нибудь.

Откуда ты знаешь, что именно занимает больше вермени. Просто по ощущению?
Возможен вариант, что происходит 2 перерисовки вместо одной (какой-нибудь лишний Invalidate невовремя).
Для начала нужно убедиться, что это не так.

Кстати, бороться с этим непросто (с лишними обновлениями), да и не нужно. Лучше (для кода) отделить перерисовку от обновления окна, разделить их. Т.е. отрисовку делать во внеэкранном буфере, а на обновление просто выплевывать его содержимое на экно. Контролировать внеэкранный буфер  нет проблем. А вот контролировать инвалидэйты сложно. Их ведь еще и система генерирует. Вообще, если перерисовка не тривиальна, лучше всегда ее делать в буфер. Кстати, для этого прекрасно бы подошел твой первый вариант, с объектом, рисующим в переданный контекст.




--------------------
...
PM   Вверх
voov
Дата 16.6.2009, 11:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Патамушта мы пилоты
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 29.11.2007

Репутация: 8
Всего: 8



Цитата(Earnest @  16.6.2009,  08:16 Найти цитируемый пост)
Вряди ли, если конечно, ты там не наворотил что-нибудь.

Может и наворотил, но не вижу где... Помоги разобраться. Возможно архитектура не оптимальная, но вроде не должна давать такую разницу.
Во фрейме лежит окно, у которого несколько детей-видов. Задача этого окна переключать виды. Одним из детей есть вид графика, у которого в свою очередь теперь есть дочернее окно - сам график.
Возможно лучше было бы убрать из этой цепочки вид, но хотелось бы сохранить функциональность, которую он предоставляет (доступ к документу и OnUpdate).


Цитата(Earnest @  16.6.2009,  08:16 Найти цитируемый пост)
Откуда ты знаешь, что именно занимает больше вермени. Просто по ощущению?

Смотрю загрузку процессора данным процессом. Дело в том, что график обновляется раз в секунду, поэтому заргузку хорошо видно. Вариант без окна примерно 8%, а с окном 15-17%. Основная программа при этом выполняет одни и те же действия, потому не может давать такой разброс.


Цитата(Earnest @  16.6.2009,  08:16 Найти цитируемый пост)
Возможен вариант, что происходит 2 перерисовки вместо одной (какой-нибудь лишний Invalidate невовремя).
Для начала нужно убедиться, что это не так.

убедился в первую очередь. провел массу тестов и экспериментов. отрисовка вызывается раз в секунду (к тому же перерисовывается не все окно, а только некоторые области).

Еще один подтверждающий симптом. 
Когда рисуется голый график, т.е. без данных, только оси, сетка, подписи и пр., то вариант без окна процессорного времени занимает очень мало, а с окном все те же 15%


Цитата(Earnest @  16.6.2009,  08:16 Найти цитируемый пост)
Лучше (для кода) отделить перерисовку от обновления окна, разделить их. Т.е. отрисовку делать во внеэкранном буфере, а на обновление просто выплевывать его содержимое на экно.

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

Перерисовка не тривиальна, но она одинакова в обоих вариантах.
А сделать окно пришлось изза необходимости инкапсулировать в класс графика обработку мыши и еще коекаких мелочей.
PM MAIL   Вверх
Earnest
Дата 17.6.2009, 08:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Т.е. не время у тебя страдает, а загрузка процессора?
Насчет однократной перерисовки - не убедил. Как я поняла, основная перерисовка вызывается по таймеру раз в секунду (т.е. Invalidate вызывается). Но где гарантия, что другие Invalidate не происходят?
Может, и не в этом причина, но я бы все же отделила код рисования графика от кода обновления и хранила буфер. Получиться дизайн более четкий. Раз в секунду (или по другому поводу) обновляется внеэкранный буфер (и вызывается Invalidate), а по OnPaint просто копируется содержимое буфера.

Цитата(voov @  16.6.2009,  12:00 Найти цитируемый пост)
А сделать окно пришлось изза необходимости инкапсулировать в класс графика обработку мыши и еще коекаких мелочей. 

Угу, знакомая картина. Только полноценное окно сюда не стоит приплетать (оболочка с ним бурно общается). Я делаю так: есть окно-вид, со станартным набором функций. И есть сменный агент-инструмент (тоже наследник CWnd, как бы двойник вида, с тем же хандлом). Поскольку это типа окно, можно вызывать все оконные процедуры и использовать карты. Но поскольку оболочка про него ничего не знает, оно получает только то, что ему передает основной вид. Преимуществ масса: управляемость, можно менять агента (разные режимы работы окна) и т.д., сразу не вспомнить, но очень удобно, поверь. Единственно, поскольку MFC не хочет присваивать один и тот же хандл разным объектам (ругается), приходится делать это аккуратно руками (т.е. вызывать Attach\Detach).
И вообще, лучший дизайн - это когда поделено все что можно. Надо пресекать расползание набора функций, иначе потом умаешься поддерживать.

Возвращаясь к твоей проблеме: попробуй задействовать профайлер и посмотри, кто жрет время. Вряд ли практически один и тот же код отрисовки модет работать с такими отличиями. 

Цитата(voov @  16.6.2009,  12:00 Найти цитируемый пост)
Вариант без окна примерно 8%,

Еще раз уточни, в чем разница между вариантами. Сейчас у тебя фрейм - вид - его дочернее окно, которое и рисует график на OnPaint (сначала в буфер, потом на экран). Так? А раньше как было?



--------------------
...
PM   Вверх
voov
Дата 17.6.2009, 14:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Патамушта мы пилоты
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 29.11.2007

Репутация: 8
Всего: 8



Цитата(Earnest @  17.6.2009,  08:34 Найти цитируемый пост)
Еще раз уточни, в чем разница между вариантами.

Уточняю.  В обоих случаях рисуется сначала в буфер, потом на экран.
Ранее: фрейм - окно (переключатель видов) - вид графика (для перерисовки вызывался метод объекта с указателем на контекст).
Сейчас: фрейм - окно (переключатель видов) - вид графика - окно графика (рисует график на OnPaint).
Еще раз отмечу, что класс графика (и оконный и просто объект) находятся в отдельной длл. Может в этом причина?


Цитата(Earnest @  17.6.2009,  08:34 Найти цитируемый пост)
Насчет однократной перерисовки - не убедил

Я ставил трэйс с текущим временем в OnPaint - по выводу было видно, что OnPaint вызывается раз в секунду.


Цитата(Earnest @  17.6.2009,  08:34 Найти цитируемый пост)
Может, и не в этом причина, но я бы все же отделила код рисования графика от кода обновления и хранила буфер

Да, наверное стоит это сделать, пусть даже из соображений дизайна.

Профайлером пока не доводилось пользоваться, потому подскажи на что там обратить внимание. Сделал пару прогонов, их самари прикрепил файлом.



Про сменный агент-инструмент. Уточню для полного понимания. Применительно к моему случаю должно получиться следующее:
- класс графика наследуется от окна, т.е. так как и сделано сейчас.
- в виде создается экземпляр графика, но не создается окно для него (Create не делаем)
- объекту графика делается Attach к HWND вида.
Другими словами в классе графика менять ничего не нужно, а нужно просто по другому использовать его?
После аттача все сообщения вида получит график, а вид ничего (будто у него нет окна)?
При этом из вида остается доступ к документу и OnUpdate будет отрабатывать точно так же?

Присоединённый файл ( Кол-во скачиваний: 5 )
Присоединённый файл  perfomance_test.jpg 100,78 Kb
PM MAIL   Вверх
Earnest
Дата 18.6.2009, 09:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



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

Цитата(voov @  17.6.2009,  15:24 Найти цитируемый пост)
- класс графика наследуется от окна, т.е. так как и сделано сейчас.
- в виде создается экземпляр графика, но не создается окно для него (Create не делаем)
- объекту графика делается Attach к HWND вида.

Немного соврала. Не Attach, а руками присваиваем. Attach проверяет, что дескриптор "свободен". Соответственно, в деструкторе обнуляем hwnd, тоже ручками. Этот объект является "недоокном": с точки зрения оболочки его нет (и никакие сообщения сами для него не дойдут), но с нашей точки зрения для него работают карты сообщений и всякие Invalidate и прочие обертки над АПИ, что очень удобно.

Цитата(voov @  17.6.2009,  15:24 Найти цитируемый пост)
После аттача все сообщения вида получит график, а вид ничего (будто у него нет окна)?
При этом из вида остается доступ к документу и OnUpdate будет отрабатывать точно так же? 

Нет, само так не получится. Все сообщения будет по прежнему получат вид (ибо именно он является представителем HWND с точки зрения оболочки). А агент получает только то, что транслирует ему вид. Таких точек может быть несколько: OnWndMsg, OnCmdMsg, OnSetCursor ... в зависимости от потребностей.
Я делаю так. В OnWndMsg делю все сообщения на 3 категории: обрабатываемые исключительно видом (они агенту не передаются), обрабатываемые и видом тоже (они обрабатываются видом вне зависимости от агента), обратываемые либо агентом либо видом. Примерно так:
Код

BOOL CMyView::OnWndMsg (UINT nMsg, WPARAM wPar, LPARAM lPar, LRESULT* pResult)
{
   if (!_IsViewExclusiveMessage (nMsg))   // просто поиск в статическом массиве
   {
      // Агенту передаются ВСЕ остальные сообщения, и раньше чем виду
      // Часть сообщений, независимо от их обработки агентом, передается и виду
      BOOL bHandled = m_pAgent->OnWndMsg (nMsg, wPar, lPar, pResult);
      if (bHandled && !_IsViewAlsoWantedMessage (nMsg))
            return TRUE;
   }
   return base_class::OnWndMsg (nMsg, wPar, lPar, pResult);
}

OnCmdMsg нужно делить, т.к. есть команды (у меня), обрабатываемые видом, и есть те, которые может обработать только агент (смысл его в том, что он сменный). Ну и т.д. WM_PAINT у меня обрабатывает вид и вызывает какой-нибудь Draw агента. 




--------------------
...
PM   Вверх
voov
Дата 18.6.2009, 11:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Патамушта мы пилоты
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 29.11.2007

Репутация: 8
Всего: 8



Цитата(Earnest @  18.6.2009,  09:08 Найти цитируемый пост)
Этот объект является "недоокном": с точки зрения оболочки его нет (и никакие сообщения сами для него не дойдут), но с нашей точки зрения для него работают карты сообщений и всякие Invalidate и прочие обертки над АПИ, что очень удобно

Но разрабатывается этот агент как обычный наследник окна с единственной поправкой на возможность установки hwnd руками. Так?

И еще. Если у агента будут дочерние окна, они смогут обрабатывать свои карты?

Это сообщение отредактировал(а) voov - 18.6.2009, 14:03
PM MAIL   Вверх
Earnest
Дата 18.6.2009, 14:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Цитата(voov @  18.6.2009,  12:14 Найти цитируемый пост)
Но разрабатывается этот агент как обычный наследник окна с единственной поправкой на возможность установки hwnd руками. Так?

Не очень понимаю, что ты имеешь в виду. Я пишу все руками, все поправки в голове держу.
Дочерние окна будут у вида - он ведь настоящее окно.  Даже если ты создашь дочернее окно, передав ему в качестве парента указатель на агента, то, во-первых, MFC может ругнуться, обнаружив несоответствие, а во-вторых, при запросе у этого чайлда парента вернет тебе таки вид.
Не нужно думать об агенте как об окне. Здесь смысл в разделении окно - содержимое. Представь, что ты пишешь логику агента, сделав его не окном, а, скажем CmdTarget. С точки зрения логической модели, это более правильно: есть окно и есть некто, модифицирующий отдельные аспекты поведения окна (любые). Причем этого некта можно менять по ходу дела (тип окна так просто не поменяешь - нужно удалять, создавать и т.д.), гладко не получится. 
Но тогда, с точки зрения реализации, придется передавать ему управление в большом числе мест + карты сообщений будут работать ограниченно (только команды) + придется передавать ему ссылку на вид (наверняка агенту потребуется что-то узнать или что-то послать). Смысл мухлежа с окном именно в удобстве реализации: сокращение числа точек передачи управления, не надо передавать вид (есть hWnd), полноценные карты... Но помнить о том, что это не совсем окно, необходимо.


--------------------
...
PM   Вверх
voov
Дата 18.6.2009, 15:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Патамушта мы пилоты
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 29.11.2007

Репутация: 8
Всего: 8



Цитата(Earnest @  18.6.2009,  14:51 Найти цитируемый пост)
Не очень понимаю, что ты имеешь в виду

Блин, когда уже наконец освою эту телепатию...  smile 

Я имел ввиду, что, если я напишу класс унаследованный от окна и добавлю к нему метод для установки hwnd, то потом смогу использовать этот класс и как окно и как агент для вида. Люблю универсальные штуки, в разумных пределах конечно.

Теперь вижу, что так гладко не получится. Хотя если трошки поднаворотить, то должно получиться.
А чтобы дочерние окна нормально работали придется давать им указатель на вид (как парент).

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.0944 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.