Гибкое профилирование - что делает [enterFrameEvent]? - PullRequest
14 голосов
/ 03 декабря 2008

Мне было поручено найти (и, возможно, исправить) некоторые серьезные проблемы с производительностью в приложении Flex, которое было нам доставлено. Приложение будет постоянно занимать от 50 до 100% процессорного времени, когда оно просто работает на холостом ходу и не должно ничего делать.

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

Лучшие 4 метода были:

  • [enterFrameEvent] - 84% совокупного, 32% самостоятельного времени
  • [пожинать] - 20% совокупного и собственного времени
  • [tincan] - 8% кумулятивного и собственного времени
  • global.isNaN - 4% совокупного и собственного времени

Все остальные методы имели менее 1% как для совокупного, так и для собственного времени.

Из того, что я нашел в Интернете, [методы в квадратных скобках] - это то, что перечисляет профилировщик, когда у него нет фактического метода Flex для отображения. Я видел, как кто-то утверждал, что [tincan] - это обработка запросов RTMP, и я предполагаю, что [reap] - сборщик мусора.

Кто-нибудь знает, что на самом деле делает [enterFrameEvent]? Я предполагаю, что это, по сути, «основная» функция для цикла обработки событий, поэтому ожидается большое кумулятивное время. Но почему у меня так много времени? Что на самом деле происходит? Я не ожидал, что внутренности плеера будут занимать так много времени, тем более что в приложении ничего не происходит (и обновления пользовательского интерфейса не происходят).

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

Ответы [ 7 ]

5 голосов
/ 09 декабря 2008

Есть пара вещей, которые обычно происходят в обработчике энтерфреймов в рамках проекта flex. Некоторые вещи, которые нужно посмотреть

  1. Ручные ответы на события или ответы, добавленные вручную через component.addEventListener (Event.ENTER_FRAME, myfunc)

  2. вызовы callLater (), они происходят в платформе ALOT и могут быть побочным продуктом перепрыгивания любого количества кроличьих ям, разработчики склонны использовать их много для решения проблем, связанных с синхронизацией, и иногда плохой код может привести к их продолжению вызывая каждый кадр. Например, в последней сборке flex sdk есть ~ 120 вхождений calllater ().

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

/ edit также, как указано ранее, [enterFrameEvent] технически должен запускаться внутренне в начале каждого кадра, но он не должен ничего делать, если к нему явно не присоединены события для выполнения пользовательского кода.

3 голосов
/ 16 апреля 2009

Обновление к этому посту, если кто-нибудь столкнется с ним в будущем ...

Несколько коллег из EffectiveUI столкнулись с этой проблемой через пару месяцев спустя, поэтому она была вновь рассмотрена. Было обнаружено, что при использовании Flash для создания визуальных ресурсов, ИСПОЛЬЗОВАНИЯ STATEFUL SKINS и экспорта их в SWC с помощью инструментария ресурсов Flash / Flex вы получаете безудержные Flash-фильмы (предположительно что-то внутреннее по отношению к тому, как это реализовано, скажем, забыв поставить команды stop () в кадрах).

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

http://patrickhansen.com/blog/index.php/2009/03/05/flex-stateful-skins-vs-stateless?blog=3

И сценарий JSFL, который можно использовать для преобразования скинов с сохранением состояния в скины без сохранения состояния:

http://patrickhansen.com/blog/index.php/2009/04/08/stateful-to-stateless-jsfl-flash-command?blog=3

Надеюсь, это кому-нибудь поможет! Это очень неприятная, таинственная ошибка, но вы можете обойти ее!

Приветствия

3 голосов
/ 05 декабря 2008

Некоторые обновления: Мы не делаем в приложении ничего, кроме прослушивания событий и использования привязок ... то есть никаких ChangeWatchers, ручного опроса ... просто ожидание событий. Мы все время подключаемся к FMS, поэтому есть некоторые накладные расходы, но они минимальны. Привязки не являются суперэффективными во Flex, и мы обнаружили, что нецелесообразно добавлять ключевое слово метаданных [Bindable] непосредственно в классы (в больших объемах, с большим количеством классов). Мы этого не делаем, но это один из способов повысить производительность вашего приложения. Если вы используете [Bindable (event = "usersUpdated")], тогда у вас есть контроль над привязкой, и она будет срабатывать только тогда, когда вы отправляете событие (new Event ("usersUpdated")) из функции в классе, т.е. сеттер для «пользователей».

Любой, кто использовал System.gc () в Flex или AIR, скажет вам, что сборка мусора в Flex - это шутка. Это частично реализованная функция, и никто не доверяет ей. Для этого тоже есть свои приемы ... позвоните дважды, подождите кадр, позвоните снова. Это может очистить ваши старые объекты, но не скрещивать пальцы ... Flex делает то, что хочет.

Также используйте временные объекты, чтобы уменьшить количество привязок. Вместо ...

myUser.location = new Location (); myUser.location.state = "CO"; myUser.location.city = "Денвер";

сделать ...

var tempLoc: Location = new Location (); tempLoc.state = "CO"; tempLoc.city = "Денвер"; myUser.location = tempLoc;

Первый запускает 3 привязки ко всему, что привязано к локации. *, В то время как последний должен запускать только 1 привязку (на самом деле она обычно дополнительная из-за способа, которым Flex ее обрабатывает).

Привязки не убьют ваше приложение, пока их не будет много в визуально насыщенном приложении ... кажется, что связывание и рендеринг - самые медленные задания Flex.

Еще одна интересная вещь: создайте новое приложение Flex3 в Flex Builder и запустите его в браузере. Наши тесты показали, что на MacBookPro процессор остается на уровне 8-10% (когда приложение бездействует, а окно браузера скрыто). Наше приложение теперь стабильно работает на уровне ~ 20%, и, хотя оно достигает пика для обработки изменений вида и т. П., Оно всегда возвращается к уровню, близкому к 20%. Наша первоначальная забота заключалась в том, что произошла утечка памяти или что-то еще, что приводило к очень высокой загрузке ЦП и оставлению зависания примерно на 40-50% (опять же, на MBP ... все относительно этой машины). Мы удалили все ссылки на Degrafa и, хотя мы заметили значительное повышение производительности, это не объясняло всего. Хотя пустое приложение Flex было поучительным - само Flex постоянно загружает 8-10% ЦП, даже в режиме ожидания.

Еще одна находка ... при использовании Mate будьте осторожны, как вы справляетесь с переключением видов. Легко иметь доступные ресурсы и просто скрывать и отключать их, когда они не используются, с помощью инжектора и привязки в MXML, но Flex не очень умен, когда дело доходит до сокрытия / отключения вещей. Лучше всего создавать представления на лету и уничтожать их, когда они будут готовы. Несмотря на то, что первоначальное создание может занять больше времени и будет больше времени ожидания между представлениями, используйте некоторую магию отображения (индикатор выполнения, вращающийся диск и т. Д.), Чтобы указать, что представление переключается, подождите, пока creationComplete в представлении, а затем исчезнуть в нем.

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

До сих пор в этой теме обсуждались основные проблемы с производительностью, характерные для любого языка, но во многих отношениях Flex - особенный маленький мальчик («особенный» не всегда считается положительным моментом). Есть бесчисленное количество подводных камней, потому что оно построено на очень визуальной платформе, но построено для RIA, поэтому, хотя Flash Player может оптимизировать видео, анимацию и т. Д., Он не оптимизирует приложение Flex. Не ожидайте, что приложения Flex будут работать так же, как приложения Flash. Существует также большая разница между AVM (виртуальной машиной ActionScript) для AS2 и AS3.

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

Код включен, ниндзя.

1 голос
/ 14 июня 2010
1 голос
/ 23 июля 2009

Эта ссылка объясняет каждую из [функций], описанных в профайлере производительности:

http://livedocs.adobe.com/flex/gumbo/html/WS6f97d7caa66ef6eb1e63e3d11b6c4d0d21-7edf.html

1 голос
/ 05 декабря 2008

Я думаю, что ваша проблема кроется в другом. Это происходит потому, что Flex построен поверх Flash, а Flash запускает это событие так же часто, как и частоту кадров (например, 20-30 раз в секунду).

http://www.adobe.com/support/flash/action_scripts/actionscript_dictionary/actionscript_dictionary546.html

РЕДАКТИРОВАТЬ: Я не говорю, что ваше решение будет снизить частоту кадров. Это сработало бы только в том случае, если вы заметили проблему. Я не уверен, что это действительно то, что вызывает твои замедления. Это может быть , вызывающая функцию, которая вызывает проблему ... но само это событие не так. Он должен много стрелять.

0 голосов
/ 05 декабря 2008

Джастин, спасибо за ответ. Проблема не в выполнении enterFrame, а в том, что он пытается сделать слишком много в каждой итерации.

К вашему сведению: случайно, мы с оригинальным постером работаем над одним и тем же приложением Мы решили удалить все ресурсы Degrafa в пользу ProgrammaticSkins. Я сообщу о результатах здесь, когда мы завершим это.

...