2008-12-03 13 views
14

Ich wurde damit beauftragt, ernsthafte Leistungsprobleme mit einer Flex-Anwendung zu finden (und möglicherweise zu beheben), die an uns geliefert wurde. Die Anwendung wird 50% bis 100% der CPU dauernd verbrauchen, wenn sie einfach im Leerlauf ist und nichts tun sollte.Flex profiling - was macht [enterFrameEvent]?

Mein erster Schritt war, den Profiler auszuführen, der mit FlexBuilder geliefert wird. Ich erwartete, eine Methode zu finden, die die meiste Zeit in Anspruch nahm und mir zeigte, wo der Engpass war. Ich habe jedoch etwas Unerwartetes bekommen.

Die oberen 4 Methoden waren:

  • [enterFrameEvent] - 84% kumulativ, 32% Selbst Zeit
  • [ernten] - 20% kumulierter und Selbstzeit
  • [tincan] - 8% kumulative und Selbst Zeit
  • global.isNaN - 4% kumulativ und Selbst Zeit

Alle anderen Methoden für beide kumulativ und Selbst Zeit weniger als 1% hatten.

Aus was ich online gefunden habe, sind die [geklammerte Methoden], was der Profiler auflistet, wenn es keine tatsächliche Flex-Methode zum Anzeigen hat. Ich sah jemanden behaupten, dass [Tincan] ist die Verarbeitung von RTMP-Anfragen, und ich nehme an, [ist ernten] ist der Garbage Collector.

Weiß jemand, was [enterFrameEvent] tatsächlich macht? Ich nehme an, es ist im Wesentlichen die "Haupt" -Funktion für die Ereignisschleife, so dass die hohe kumulative Zeit erwartet wird. Aber warum ist die eigene Zeit so hoch? Was geht eigentlich vor? Ich habe nicht erwartet, dass die Interna des Players so viel Zeit in Anspruch nehmen, zumal nichts in der App passiert (und es gibt keine Updates für die Benutzeroberfläche).

Gibt es einen guten Weg, um herauszufinden, was passiert? Ich weiß etwas ist los, das sollte nicht sein (es sieht aus wie muss es eine Art beschäftigt warten oder andere unkontrollierbare Schleife), aber der Profiler gibt mir keine Ergebnisse, die ich erwartet hatte. Mein nächster Schritt wird sein, Debug-Trace-Anweisungen an verschiedenen Stellen hinzuzufügen, um zu versuchen, herauszufinden, was tatsächlich passiert, aber ich habe das Gefühl, dass es einen besseren Weg geben muss.

Antwort

1

Ich denke, dein Problem liegt woanders. Dies geschieht, weil Flex auf Flash basiert und Flash dieses Ereignis genauso häufig wie die Framerate auslöst (etwa 20-30 Mal pro Sekunde).

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

EDIT: Ich sage nicht, Ihre Lösung, um die Framerate zu senken wäre. Das würde nur funktionieren, wenn das Ereignis, das du bemerkt hast, das Problem war. Ich bin nicht davon überzeugt, dass dies Ihre Verlangsamung verursacht. Es kann die Aufruf eine Funktion sein, die das Problem verursacht ... aber das Ereignis selbst ist es nicht. Es soll viel feuern.

+0

Ich habe versucht zu spielen um mit der Framerate, aber es hatte keinen wirklichen Effekt auf die Leistung. Wenn Sie die Framerate zu stark verringern, würde dies dazu führen, dass die Änderungen an der Benutzeroberfläche zu langsam ablaufen und die angezeigten Probleme nicht beheben. – Herms

+0

Die Sache ist, der Profiler behauptet, dass das Ereignis ITSELF 32% der CPU-Zeit einnimmt (es plus, was es fordert, nimmt 84%). Das ist sehr viel Zeit für eine Veranstaltung. Etwas ist los, aber ich kann nicht sagen, was. – Herms

0

Justin, danke für die Antwort. Das Problem besteht nicht darin, dass enterFrame ausgeführt wird, sondern dass versucht wird, in jeder Iteration zu viel zu tun.

FYI: Zufällig haben das ursprüngliche Plakat und ich mit der gleichen Anwendung zu tun. Wir haben entschieden, alle Ressourcen von Defrafa zugunsten von ProgrammaticSkins zu entfernen. Ich werde die Ergebnisse hier berichten, wenn wir dies abgeschlossen haben.

3

Einige Updates: Wir machen nichts in der App, außer auf Ereignisse zu horchen und Bindings zu verwenden ... das heißt, keine ChangeWatchers, keine manuelle Abfrage ... nur auf Ereignisse wartend. Wir sind die ganze Zeit über mit FMS verbunden, es gibt also einen gewissen Overhead dafür, aber es ist minimal. Bindungen sind in Flex nicht besonders effizient, und wir haben festgestellt, dass es nicht gut ist, das Metadaten-Schlüsselwort [Bindable] direkt zu Klassen hinzuzufügen (in großen Mengen, mit vielen Klassen). Wir machen nicht viel davon, aber es ist eine Möglichkeit, etwas mehr Leistung aus Ihrer App herauszuholen. Wenn Sie [Bindable (event = "usersUpdated")] verwenden, haben Sie die Kontrolle über die Bindung, und sie wird nur ausgelöst, wenn Sie das Ereignis (new) ("usersUpdated") aus einer Funktion in der Klasse dispathen Setter für "Benutzer".

Jeder, der System.gc() in Flex oder AIR verwendet, wird Ihnen sagen, dass Flex Garbage Collection ein Witz ist. Es ist ein teilweise implementiertes Feature und niemand vertraut ihm. Dazu gibt es auch Tricks ... Ruf zweimal an, warte einen Frame, rufe ihn erneut an. Es könnte Ihre alten Objekte aufräumen, aber drücken Sie nicht die Daumen ... Flex macht, was es will.

Verwenden Sie auch temporäre Objekte, um die Anzahl der abgefeuerten Bindungen zu verringern. Statt ...

myUser.location = neuer Standort(); myUser.location.state = "CO"; myUser.location.city = "Denver";

do ...

var tempLoc: Location = new Location(); tempLoc.state = "CO"; tempLoc.city = "Denver"; myUser.location = tempLoc;

Die ehemaligen Brände 3 Bindungen an etwas Ort gebunden. *, Während die letzteren sollten (es ist in der Regel zusätzlichen aufgrund der Art und Weise Flex es in Wirklichkeit behandelt.) Nur Feuer 1-Bindung

Bindungen nicht Ihrem töten App, bis Sie eine Menge von ihnen in einer visuell reichen Anwendung haben ... Bindung und Rendering scheinen die langsamsten Jobs von Flex zu sein.

Eine weitere interessante Sache: Erstellen Sie eine brandneue Flex3-Anwendung in Flex Builder und führen Sie sie im Browser aus. Unsere Tests haben gezeigt, dass die CPU auf einem MacBookPro zwischen 8-10% bleibt (wenn sich die App im Leerlauf befindet und das Browserfenster ausgeblendet ist). Unsere Anwendung läuft jetzt konstant bei ~ 20% und während sie höher abspringt, um Änderungen der Ansicht und dergleichen zu handhaben, kehrt sie immer auf ein Niveau nahe 20% zurück. Unsere anfängliche Sorge war, dass ein Speicherleck oder etwas, das wegrennt, die CPU sehr hoch nehmen und es um 40-50% schweben lassen würde (wieder auf dem MBP ... alles relativ zu diesem Rechner). Wir haben alle Referenzen zu Degrafa herausgenommen und während wir ein gutes Stück Leistungssteigerung bemerkten, hat es nicht alles berücksichtigt. Die leere Flex-App war jedoch aufschlussreich - Flex selbst schwemmt immer 8-10% CPU, selbst im Leerlauf.

Noch ein weiterer Fund ... wenn Sie Mate verwenden, seien Sie vorsichtig, wie Sie mit dem Wechseln von Ansichten umgehen. Es ist einfach, Assets verfügbar zu haben und einfach zu verstecken & deaktivieren Sie sie, wenn sie nicht verwendet werden, mit einem Injektor und einer Bindung in MXML, aber Flex ist nicht sehr schlau, wenn es darum geht, Dinge zu verbergen/deaktivieren. Es ist am besten, die Ansichten spontan zu erstellen und sie zu zerstören, wenn sie fertig sind. Auch wenn die anfängliche Erstellung mehr Zeit in Anspruch nimmt und zwischen den Ansichten länger gewartet werden muss, verwenden Sie einige Anzeigemagie (Fortschrittsbalken, drehende Festplatte usw.), um anzuzeigen, dass die Ansicht wechselt, auf createComplete in der Ansicht wartet und dann verblassen Sie hinein.

Auch weg von ViewStack für visuell reichhaltige Anwendungen. Verwalte deinen eigenen Stapel.

Bisher wurden in diesem Thread die grundlegenden Leistungsprobleme jeder Sprache behandelt, aber Flex ist in vielerlei Hinsicht ein ganz besonderer kleiner Junge ("Special" wird nicht immer als positive Sache angesehen). Es gibt unzählige Fallstricke, da es auf einer sehr visuellen Plattform aufbaut und dennoch für RIAs entwickelt wurde. Flash Player optimiert also möglicherweise Videos, Animationen usw. und optimiert somit keine Flex-App. Erwarten Sie nicht, dass Flex-Apps dieselben Funktionen wie Flash-Apps ausführen. Es gibt auch einen großen Unterschied zwischen AVM (ActionScript Virtual Machine) für AS2 und AS3.

Dies ist nur die Oberfläche der Leistungsprobleme und potenzielle Gewinne in Flex-Apps kratzen. Dies ist eine dunkle Kunst und es ist leicht zu sehen warum.

Code auf, Ninjas.

+0

Nur zur Info: eine leere Flex-App auf meinem Rechner läuft durchgängig bei 0% CPU. Ich werde es später auf einer beschissenen alten Schachtel testen, um zu sehen, ob es anders ist. Ich denke also nicht, dass das eine besonders nützliche Sache ist, da die Performance-Probleme, die wir in der App haben, auch in Windows sind. – Herms

5

Es gibt ein paar Dinge, die typischerweise auf einem Enterframe-Handler innerhalb eines Flex-Projekts passieren. Einige Dinge zu beobachten für

  1. Handbuch < MyComponent enterframe = ""> Ereignisantworten oder Einsen hinzugefügt manuell über component.addEventListener (Event.ENTER_FRAME, myfunc)

  2. calllater() aufruft, diese ALOT passieren im Rahmen und kann Nebenprodukt des Herabspringens eine beliebige Anzahl von Kaninchen Löcher, Entwickler neigen dazu, diese viel zu lösen Timing Probleme und manchmal schlechten Code kann dazu führen, dass weiterhin jeden Rahmen aufrufen. Zum Beispiel gibt es ~ 120 Vorkommen eines Calllater() in der letzten Flex-SDK-Build.

  3. schließlich kann ich nicht garantieren, dass das [enterframeEvent] nur enterframe-spezifische Ereignisrückrufe verarbeitet, und nicht Timer, Maus usw. Ereignisse, da enterframes während der Hauptereignisschleife auftreten, sehen Sie möglicherweise die kumulative Ergebnis aller Ereignisse aus dem Main Event Pool. Ich sage nicht, das ist was passiert, aber ich kann nicht sagen, es ist auch nicht was passiert, ich weiß nicht genug über die Interna dort, um sicher zu sein.

/bearbeiten auch wie bereits erwähnt, die [enterFrameEvent] sollte technisch intern zu Beginn jedes Rahmens Feuer, aber es sollte nichts tun, es sei denn, Veranstaltungen, um es explizit angebracht worden Benutzercode auszuführen.

+0

Aber alle Methoden, die an CallLater übergeben oder als Listener hinzugefügt wurden, sollten im Profiler angezeigt werden, oder? Da dies tatsächliche AS3-Methoden wären, würde ich erwarten, dass die Zeit in diesen Methoden angezeigt wird, nicht innerhalb von enterFrameEvent selbst. Das ist seltsam. – Herms

+0

Ja und nein, enterframeEvent wäre ein kumulatives Ergebnis von allem, wenn Sie 10 oder 20 Rückrufe während dieses Ereignisses verarbeitet haben, könnten sie alle geringfügig sein und nicht so viel im Profiler separat registrieren, aber zusammen repräsentieren sie viel Zeit. – seanalltogether

+0

Der Profiler zeigt 2 Werte. Kumulativ und Selbst Kumulativ ist, wovon du sprichst. Ich glaube, dass Selbst ist, wie viel Zeit in dieser Methode speziell verbracht wird, und nicht in den anderen profilierten Methoden. – Herms

3

Ein Update auf dieses Thema sollte später mit ihrem Antrag ein paar Monate

Einige Mitarbeiter an EffectiveUI hatte genau dieses Problem für sie in der Zukunft ... jemand kommen, so ist es revisited wurde. Es wurde entdeckt, dass wenn Flash Flash verwendet, um visuelle Assets zu erstellen, SKUTS BENUTZEN und mit dem Flash/Flex Asset-Toolkit nach SWC exportiert werden, Flash-Filme laufen (vermutlich etwas, das der Art und Weise entspricht, wie das implementiert wird, sagen wir mal vergessen) stop() Befehle in Frames).

Es gibt offensichtlich nichts, was Sie dagegen tun können, außer alle Stateful Skins zu entfernen. Ein gutes write-up ist hier zu finden:

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

Und ein JSFL Skript, das Sie Stateful-Skin verwenden kann, um konvertieren Häute auf stateless:

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

hoffte, das hilft jemand! Es ist ein sehr böser, mysteriöser Bug, aber du kannst es umgehen!

Prost