Memory allocations are not free

29 January 2013

Tags

  • Fairy Tale Twist
  • Performance
  • Starling

The premise for this investigation was allocating memory is not free. Allocating memory is not free, freeing memory is not free, garbage collection is not free. Some preparation is required. The Adobe Profiler (predecessor for Adobe Scout) tracks memory usage but filters out the Adobe API. Instead, Ben Garney, previously of Push Button Labs, and I worked on a profiler that uses the Sampler API directly and does not filter results. It can be downloaded here: https://github.com/bengarney/PBLabsProfiler/downloads

PBLabsProfiler Beta

his is a utilitarian profiler for use with Flash. It works with the flash.sampler API. The PBLabsProfiler is licensed under the GPLv3. The code is (c) 2010 Ben Garney. If you’d like to use it under a different license please contact Ben at ben DOT garney AT gmail DOT com. There is an official forum for discussion, troubleshooting, and announcements on the PushButton Engine site. Thanks to PushButton Labs for donating forum space.

Prerequisites

You need to be on a supported OS. Currently the prebuilt binary only works on OS X. (See the Hacking PBLabsProfiler section below for details on building for other platforms.) You need to have a recent JRE installed. We have been using Java 2 Runtime Edition 1.5. If you are on OS X you already have this. If you are on windows, get the most recent JRE.

Running The Binary

If you have received a prepackaged ZIP with a JAR in it, you do not need to compile any files to use the profiler. Follow these steps: Unzip the PBLabsProfiler.zip to a location of your choosing. If you are on Mac, open the terminal and run these commands:

chmod u+x PBLabsProfiler.sh ./PBLabsProfiler.sh

If you are on Windows, launch the windows JAR with the following command:

javaw PBLabsProfiler-Win32.jar

You may also be able to double click the JAR and launch it. Confirm that the PBLabsProfiler app has come up and shown its UI. You should see output like the following: INFO: PBLabs Profiler server started on localhost:4262 Close all web browsers and Flash Player instances.

mm.cfg is only checked when Flash Player starts globally.

You may need to modify the mm.cfg file and restart your system. Find mm.cfg (see section 3), and: Add a line like:

PreloadSwf=/path/to/PBLabsProfiler/Agent.swf

You might want to turn on logging to a file, it makes debugging the stub a great deal simpler. Mine reads like this:

PreloadSwf=/path/to/PBLabsProfiler/Agent.swf TraceOutputFileEnable=1 ErrorReportingEnable=1 MaxWarnings=1000000 TraceOutputBuffered=1

On OS X, your mm.cfg can be found in your home directory (you may have to create it if it doesn’t exist), and your flashlog.txt can be found in ~/Library/Preferences/Macromedia/Flash Player/Logs/flashlog.txt, once you have your mm.cfg set up properly. If everything seems right and you have no flashlog.txt, try rebooting. Add Agent.swf to the list of trusted files using the Flash Player Settings Manager Open Flash content with the Flash debug player active/installed. The profiler will automatically open new windows for each profiled SWF. Currently closing windows results in a crash.

Hacking on PBLabsProfiler

If you want to compile this tool from scratch or develop it, please read the following. The AS3 profiling stub is based on http://github.com/osi/flash-profiler. The Java client is written from scratch using SWT.

Prerequisites

Flex SDK 4.0.0 Eclipse Java development environment. You don’t need the EE version.

Compile

Compile Agent.as to Agent.swf. I use:

mxmlc Agent.as -target-player=10

Compile and run the Java project using Eclipse. FlashProfiler.java is the main class. Add all the .jars to your class path. You may need to get the appropriate version of SWT for your platform.

Usage

Launch the profiler from Eclipse. You may have to pass the -XstartOnFirstThread command line/VM option for it to work on OS X. -d32 may also be required if you have 64bit VM. Continue with the first set of usage instructions starting with step 4. —-But I recommend you install from source and compile yourself. If you need Eclipse for Java is can be downloader here: http://www.eclipse.org/downloads/ and start a new project form the javaClient /Users/rgale/projects/PBLabsProfiler/javaClient. Under Project Properties, Java Build Path choose Add External JARs and add the following: swt-debug.jar mina-core.jar slf4j-api-1.5.11.jar slf4j-jdk-1.5.11.jar and under Run configurations, VM arguments add: -XstartOnFirstThread -d32 You will also need a mm.cfg, under OSX this should be created/edited at ~/mm.cfg PreloadSwf=/Users/rgale/projects/PBLabsProfiler/flashStub/Agent.swf TraceOutputFileEnable=1 ErrorReportingEnable=1 MaxWarnings=1000000 TraceOutputBuffered=1

Map screen, idle 2 minutes

4.7 allocations/frame ([enterFrameEvent]/starling.core::get contextValid, 32973/6884).

This is good.

  • 32973 [enterFrameEvent]
  • 11547    starling.core::onEnterFrame
  • 11547        starling.core:: nextFrame
  • 11338            starling.core:: render
  • 6884                 starling.core::get contextValid
  • 4454                 starling.display::DisplayObjectContainer/render …
  • 4454                     starling.text::TextField/createRenderedContents
  • 2358                         starling.text::TextField/updateNativeTextField
  • 1048                         starling.textures::fromBitmapData
  • 131                          starling.display::Image/readjustSize
  • 656      com.greensock::TweenLite/updateAll
  • 118      BaseGame/onEngineEnterFrame
  • 15519 flash.utils::Timer/tick
  • 15501     flash.utils::Timer/_timerDispatch
  • 3497          Array/get length, Date/get time

Recommendations

  • Profile performance before and after any of the recommendations below.
  • Consider memory pooling.
  • Investigate ParticlePool and particles, pool may not be adding much as particles are all in a single vertex/index buffer. Consider starting with a large buffer and not doubling it’s size (initial capacity is 128 and maxing at 8192)
  • Consider replacing ColorArgb type in PDParticle with basic types, e.g. Number, this would save two allocations per particle, the color would still be combined into a structure during the update.
  • For real dates use Date() for everything else use TimeUtil.serverTimeSeconds (which in turn uses getTimer() that does no allocations) (there are 18 instances of new Date()
  • Move texture packing offline (responsible for 10020 allocations of 771 frames)
  • SetIntervalTimer/onTimer is interesting, ends up calling removeChild via an apply()

General recommendations

Try x, y pairs rather than new Point() (there are 144 matches for new Point in the game code) and new Rectangle() (there are 29 matches for new Rectangle) especially when using as a container, passing variables, i.e. not using union.