<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.mozilla.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Joel+Reymont</id>
	<title>MozillaWiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.mozilla.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Joel+Reymont"/>
	<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/Special:Contributions/Joel_Reymont"/>
	<updated>2026-08-18T02:23:56Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.10</generator>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements&amp;diff=188643</id>
		<title>Firefox/Projects/Startup Time Improvements</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements&amp;diff=188643"/>
		<updated>2009-12-10T14:25:01Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Measuring Ts */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&#039;&#039;&#039;Project lead:&#039;&#039;&#039; Dietrich Ayala &amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Project members:&#039;&#039;&#039; Ryan Flint, Drew Willcoxon, David Dahl, Vlad Vukićević, Taras Glek, Joel Reymont, Ben Hsieh&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Investigate areas for improving startup time of the Mozilla platform, find &amp;amp; fix issues that help Fennec and WinCE.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bugs:&#039;&#039;&#039;&lt;br /&gt;
* [http://tinyurl.com/ygbnzmd Open] (identified by &amp;quot;[ts]&amp;quot; in the whiteboard field)&lt;br /&gt;
* [http://tinyurl.com/yjp8d6w Fixed]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Results&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See results in the [http://people.mozilla.org/~dietrich/snapshot/ Performance Snapshot].&lt;br /&gt;
&lt;br /&gt;
= Projects =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Areas of Work:&#039;&#039;&#039;&lt;br /&gt;
* minification&lt;br /&gt;
** {{bug|524858}} - minify js&lt;br /&gt;
** {{bug|513132}} - minify css&lt;br /&gt;
** {{bug|523479}} - minify extension&#039;s contents&lt;br /&gt;
* file combining&lt;br /&gt;
** {{bug|507101}} - combining js components&lt;br /&gt;
** {{bug|509755}} - put modules into a jar&lt;br /&gt;
* {{bug|FILEME}} - [https://bugzilla.mozilla.org/show_bug.cgi?id=279839#c29 string pool for jsxpcom]&lt;br /&gt;
* taking advantage of tracing&lt;br /&gt;
** figure out where we&#039;re not tracing in the startup log&lt;br /&gt;
** [http://blog.mozilla.com/dmandelin/2009/02/26/tracevis-performance-visualization-for-tracemonkey/ dmandelin&#039;s blog post]&lt;br /&gt;
** traceviz ({{bug|497999}})&lt;br /&gt;
* [[Firefox/Projects/Startup_Time_Improvements/Static_Build|static build]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Measurement &amp;amp; Testing&#039;&#039;&#039;&lt;br /&gt;
* cold startup testing&lt;br /&gt;
** &amp;lt;strike&amp;gt;{{bug|510587}} - mac and linux&amp;lt;/strike&amp;gt;&lt;br /&gt;
** {{bug|522807}} - windows&lt;br /&gt;
* dirty profile testing&lt;br /&gt;
** &amp;lt;strike&amp;gt;{{bug|414660}} - infrastructure &amp;amp; places&amp;lt;/strike&amp;gt;&lt;br /&gt;
** {{bug|515540}} - dirty+cold startup&lt;br /&gt;
** {{bug|527596}} - dirty Tp (teehee)&lt;br /&gt;
** {{bug|FILEME}} - test an all-dirty profile&lt;br /&gt;
** {{bug|FILEME}} - other dirty profiles&lt;br /&gt;
* micro-benchmarking&lt;br /&gt;
** {{bug|523146}} - test framework&lt;br /&gt;
** {{bug|479528}} - for location bar&lt;br /&gt;
** {{bug|451607}} - for places UI&lt;br /&gt;
** {{bug|479528}} - for places SQL&lt;br /&gt;
** more, eg: test for opening the 80th tab&lt;br /&gt;
* built-in startup measurement ({{bug|522375}})&lt;br /&gt;
** user-runnable Ts script, paste into js console&lt;br /&gt;
** restarts browser, passing last known time&lt;br /&gt;
** loads data URI that reads startup time and prints it out&lt;br /&gt;
** record startup timestamp as a pref?&lt;br /&gt;
* timeline of the startup path (David, Vlad)&lt;br /&gt;
** Status: incomplete (held up on hangs, nspr changes)&lt;br /&gt;
** [https://wiki.mozilla.org/Firefox/Sprints/Startup_Time_Improvements/StartupPatchUsage#Quick_Start docs]&lt;br /&gt;
** {{bug|480735}} instrumentation&lt;br /&gt;
** {{bug|503605}} visualization ([http://mozilla.ddahl.com/startup/timeline-similie.html Simile timeline], [http://people.mozilla.org/~dietrich/ddahl_sample_output.txt raw log])&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Docs:&#039;&#039;&#039;&lt;br /&gt;
* write best practices recommendation&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inactive Projects&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Mine the Ts DTrace viz/logs (Drew)&lt;br /&gt;
** Status: complete, moved on to filesystem operations below&lt;br /&gt;
** Results&lt;br /&gt;
*** cold startup is heavily I/O-bound. 90% of cold startup time is spent in page faults and other I/O syscalls, especially read, getattrlist, and stat.&lt;br /&gt;
*** majority of time spent after Firefox actually gets up and running is in XBL and CSS.&lt;br /&gt;
* Log and mine filesystem operations during startup (Ryan, Drew)&lt;br /&gt;
** Status: complete, bugs filed for egregious offenders&lt;br /&gt;
** Results&lt;br /&gt;
*** checking out Xperf and others for Windows work&lt;br /&gt;
*** investigating dtrace timing/FS cache issues on OS X&lt;br /&gt;
**** Instruments appears to have the same issues&lt;br /&gt;
*** Simple JS file exec script has yielded [https://bugzilla.mozilla.org/buglist.cgi?bug_id=504513 some results]&lt;br /&gt;
** References&lt;br /&gt;
*** [http://boomswaggerboom.wordpress.com/2009/06/24/firefox-for-mac-os-x-and-filesystem-related-system-calls/ Josh Aas&#039;s post on filesystem calls]&lt;br /&gt;
*** [http://blog.mozilla.com/tglek/2009/07/01/python-gdb-logging-file-io/ Taras&#039; post] on using GDB for logging&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/IO_Scratchpad]]&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/adw_notes|Drew&#039;s notes]]&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/joelr_notes|Joel&#039;s notes]]&lt;br /&gt;
* Find dead code with JSHydra (David Dahl)&lt;br /&gt;
** Status: incomplete, needs tuning and file bugs on dead code found&lt;br /&gt;
** {{bug|506128}} - run jshydra to find js functions that have no callers&lt;br /&gt;
* JSHydra continuous testing&lt;br /&gt;
** possible test scenarios&lt;br /&gt;
*** ending semicolon bug (XXX)&lt;br /&gt;
*** dead code finder&lt;br /&gt;
&lt;br /&gt;
=Status Updates=&lt;br /&gt;
&lt;br /&gt;
* [http://autonome.wordpress.com/2009/10/02/firefox-startup-performance-weekly-summary-4/ 10/2/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/26/firefox-startup-performance-weekly-summary-3/ 9/26/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/18/firefox-startup-performance-weekly-summary-2/ 9/18/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/06/firefox-startup-performance-weekly-summary/ 9/6/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/29/firefox-startup-performance-weekly-roundup/ 8/29/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/22/weekly-firefox-startup-performance-roundup-2/ 8/22/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/18/firefox-performance-the-dont-touch-the-damn-disk-edition/ 8/18/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/08/firefox-startup-performance/ 8/8/09]&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&lt;br /&gt;
;Meta bugs&lt;br /&gt;
* {{bug|459117}} Fennec performance meta bug&lt;br /&gt;
* {{bug|447581}} Startup meta bug&lt;br /&gt;
* {{bug|479078}} Startup research meta bug&lt;br /&gt;
* {{bug|7251}} very old startup meta bug&lt;br /&gt;
&lt;br /&gt;
* Vlad&#039;s blog posts&lt;br /&gt;
** [http://blog.vlad1.com/2009/06/17/firefox-startup-wrangling/ Vlad&#039;s June posting on startup work]&lt;br /&gt;
** Vlad&#039;s July posts:&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/27/startup-part-1/ 1]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/27/startup-again/ 2 - fs cache]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/28/startup-again-2/ 3 - event processing]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/28/measuring-startup/ 4 - measuring startup] &lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/29/startup-again-3/ 5 iosnoop]&lt;br /&gt;
&lt;br /&gt;
* zpao&#039;s JS treemap visualizations&lt;br /&gt;
** [http://playground.zpao.com/dtrace_treemaps2/ newer]&lt;br /&gt;
** [http://playground.zpao.com/dtrace_treemaps/ older]&lt;br /&gt;
&lt;br /&gt;
* Taras&#039; Fennec Startup Work&lt;br /&gt;
** {{bug|459117}} &amp;quot;make fennec faster&amp;quot;, mostly startup bugs&lt;br /&gt;
** [http://people.mozilla.com/~tglek/fennec/startup.txt startup log]&lt;br /&gt;
** {{bug|470116}} various timing scripts&lt;br /&gt;
&lt;br /&gt;
* [[Performance:Home_Page]]&lt;br /&gt;
&lt;br /&gt;
==Tips, Tools==&lt;br /&gt;
&lt;br /&gt;
* Cold startup&lt;br /&gt;
** [http://aegisknight.org/2009/04/flushing-disk-cache/ Flushing Windows&#039; disk cache]&lt;br /&gt;
** [http://tuvix.apple.com/DOCUMENTATION/Darwin/Reference/ManPages/man8/purge.8.html Flushing Mac OS X&#039;s disk cache]&lt;br /&gt;
** [[Firefox/Projects/Startup_Time_Improvements_Notes]]: Vlad&#039;s emails about cold startup, including Linux (maybe move this info to this page)&lt;br /&gt;
&lt;br /&gt;
* Windows Prefetch/Superfetch&lt;br /&gt;
** [http://en.wikipedia.org/wiki/Prefetcher XP Prefetch wiki]&lt;br /&gt;
** [http://en.wikipedia.org/wiki/Windows_Vista_I/O_technologies#SuperFetch Vista/Win7 SuperFetch wiki]&lt;br /&gt;
** [http://members.rushmore.com/~jsky/id37.html useful Pre/SuperFetch overview]&lt;br /&gt;
** [http://jessekornblum.com/presentations/dodcc08-2.html Presentation slides on the guts of Pref/SuperFetch by military forensic analyst]&lt;br /&gt;
*** Prefetch&lt;br /&gt;
**** Profile for each application: List of DLLs used, Run count, Time stamps&lt;br /&gt;
**** Prefetch files stored in %SystemRoot%\Prefetch: .pf extension, Up to 128 are kept&lt;br /&gt;
**** Can tell if same app run from multiple locations&lt;br /&gt;
*** SuperFetch&lt;br /&gt;
**** turn off: net stop sysmain&lt;br /&gt;
**** AG*.db files, contain &amp;quot;scenarios&amp;quot; for preloading&lt;br /&gt;
** [http://technet.microsoft.com/en-us/magazine/2007.03.vistakernel.aspx Technet article on Vista mem mgmnt]&lt;br /&gt;
** [http://www.howtogeek.com/howto/windows-vista/change-superfetch-to-only-cache-system-boot-files-in-vista/ registry keys for toggling SuperFetch]&lt;br /&gt;
&lt;br /&gt;
* DTrace&lt;br /&gt;
** [https://wiki.mozilla.org/Performance/Optimizing_JavaScript_with_DTrace nuts and bolts how-to for getting dtrace running with mozilla]&lt;br /&gt;
** [http://www.opensolaris.org/os/project/mozilla-dtrace/ project overview of integrating dtrace with mozilla]&lt;br /&gt;
** [http://www.opensolaris.org/os/community/dtrace/ dtrace community page, lots of links]&lt;br /&gt;
** [http://www.sun.com/bigadmin/content/dtrace/ dtrace homepage? not as useful as previous link]&lt;br /&gt;
** [http://wikis.sun.com/display/DTrace/Introduction intro from dtrace guidebook, really useful but not mozilla/js-specific]&lt;br /&gt;
** [http://blogs.sun.com/jmr/entry/dtrace_mozilla_rfe_javascript_tracing brief descriptions of the javascript* probes]&lt;br /&gt;
** [http://blog.mozilla.com/dmandelin/2008/02/14/dtrace-c-mysteries-solved/ David Mandelin&#039;s notes on tracing C++ code]&lt;br /&gt;
&lt;br /&gt;
* comparing dynamic linking time between firefox and safari on mac&lt;br /&gt;
** DYLD_PRINT_STATISTICS=YES /Applications/Firefox.app/Contents/MacOS/firefox-bin&lt;br /&gt;
** DYLD_PRINT_STATISTICS=YES open -a Safari&lt;br /&gt;
&lt;br /&gt;
==Fastload==&lt;br /&gt;
* why does js_Execute take so long for fastloaded components?&lt;br /&gt;
* [http://groups.google.com/group/mozilla.dev.platform/browse_thread/thread/42c0e9df84b935fe what is fastload?]&lt;br /&gt;
* [http://kb.mozillazine.org/Nglayout.debug.disable_xul_fastload fastload pref docs]&lt;br /&gt;
&lt;br /&gt;
==Measuring Ts==&lt;br /&gt;
&lt;br /&gt;
We&#039;ve been using a method Vlad blogged about [http://blog.vlad1.com/2009/07/28/measuring-startup/ here]. The steps are below.&lt;br /&gt;
&lt;br /&gt;
# save [http://people.mozilla.com/~vladimir/misc/startup.html this html file] somewhere locally&lt;br /&gt;
# create a new profile, run Firefox with it at least once, so all files are created, etc&lt;br /&gt;
# execute this command, with your profile name substituted, and invoking firefox in a way appropriate for your platform:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
./firefox -P YourProfileName -no-remote file:///..../startup.html#`python -c &#039;import time; print int(time.time() * 1000);&#039;`&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is specific to Mac OSX and is required to evict Firefox code pages from memory and clear the Unified Buffer Cache (UBC). &amp;lt;code&amp;gt;purge&amp;lt;/code&amp;gt; does NOT do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
FF=/Volumes/Fujitsu80Gb&lt;br /&gt;
&lt;br /&gt;
diskutil unmount force $FF&lt;br /&gt;
diskutil mount /dev/disk1s2&lt;br /&gt;
&lt;br /&gt;
$FF/Minefield$*.app/Contents/MacOS/firefox-bin -no-remote -foreground -P clean file://$FF/startup.html#`python -c &#039;import time; print int(time.time() * 1000);&#039;`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This assumes that your removable media is at /dev/disk1s2.&lt;br /&gt;
&lt;br /&gt;
==Test Coverage==&lt;br /&gt;
&lt;br /&gt;
This is an index of Firefox startup scenarios which need automated test coverage.&lt;br /&gt;
&lt;br /&gt;
TODO:&lt;br /&gt;
* groups: chrome, content, extensions, labs, other?&lt;br /&gt;
* mark which need no-chrome testing&lt;br /&gt;
&lt;br /&gt;
{| border=solid black 1px&lt;br /&gt;
| test || warm start || cold start || notes&lt;br /&gt;
|-&lt;br /&gt;
| empty profile ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||&lt;br /&gt;
|-&lt;br /&gt;
| everything dirty || || || {{bug|515540}}&lt;br /&gt;
|-&lt;br /&gt;
| min places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || informed by places-stats, {{bug|515540}}&lt;br /&gt;
|-&lt;br /&gt;
| med places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || ditto&lt;br /&gt;
|-&lt;br /&gt;
| max places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || ditto&lt;br /&gt;
|-&lt;br /&gt;
| med session || || || informed by test pilot data&lt;br /&gt;
|-&lt;br /&gt;
| max session || || || ditto&lt;br /&gt;
|-&lt;br /&gt;
| downloads || || ||&lt;br /&gt;
|-&lt;br /&gt;
| url-classifier data || || || data is fully downloaded, should test page-load for a match and no match&lt;br /&gt;
|-&lt;br /&gt;
| form history|| || ||&lt;br /&gt;
|-&lt;br /&gt;
| passwords || || ||&lt;br /&gt;
|-&lt;br /&gt;
| plugins || || ||&lt;br /&gt;
|-&lt;br /&gt;
| content preferences || || ||&lt;br /&gt;
|-&lt;br /&gt;
| extensions || || || top 5?&lt;br /&gt;
|-&lt;br /&gt;
| extension update || || ||&lt;br /&gt;
|-&lt;br /&gt;
| application update || || ||&lt;br /&gt;
|-&lt;br /&gt;
| persona applied || || ||&lt;br /&gt;
|-&lt;br /&gt;
| weave || || ||&lt;br /&gt;
|-&lt;br /&gt;
| jetpack || || ||&lt;br /&gt;
|-&lt;br /&gt;
| ubiquity || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page links are visited || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page has microformats || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page is ssl || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page has plugin || || ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/Static_Build&amp;diff=187820</id>
		<title>Firefox/Projects/Startup Time Improvements/Static Build</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/Static_Build&amp;diff=187820"/>
		<updated>2009-12-04T21:49:43Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
A static build nets us a ~15% startup performance win on the Mac. A static build breaks XPCOM components, though, so a solution needs to be provided.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bugs&#039;&#039;&#039;&lt;br /&gt;
* {{bug|525013}} - investigate a more static build configuration of Firefox&lt;br /&gt;
** {{bug|532531}} - make binary components work on the Mac&lt;br /&gt;
** {{bug|532769}} - get a Linux static build going&lt;br /&gt;
** {{bug|532763}} - make binary components work on Linux&lt;br /&gt;
** {{bug|532771}} - get a Windows static build going&lt;br /&gt;
** {{bug|532765}} - make binary components work on Windows&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Results&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
There are no issues on Mac or Linux but Windows seems to build a dependency on firefox.exe into the components (see {{bug|532765}}).&lt;br /&gt;
&lt;br /&gt;
We definitely want to use _-mdynamic-no-pic_ on the Mac. At one point in time this resulted in a 50% startup boost when running from an external USB HD. The next day we were down to a more reasonable 15%. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Areas of work&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Results definitely need to be verified on all platforms. Need to fix our cold startup harness on the Mac to fully clear the OS caches ({{bug|532965}}).&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/Static_Build&amp;diff=187815</id>
		<title>Firefox/Projects/Startup Time Improvements/Static Build</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/Static_Build&amp;diff=187815"/>
		<updated>2009-12-04T21:40:16Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: Created page with &amp;#039;= Overview = &amp;#039;&amp;#039;&amp;#039;Description:&amp;#039;&amp;#039;&amp;#039;   A static build nets us a ~15% startup performance win on the Mac. A static build breaks XPCOM components, though, so a solution needs to be prov…&amp;#039;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
A static build nets us a ~15% startup performance win on the Mac. A static build breaks XPCOM components, though, so a solution needs to be provided.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bugs:&#039;&#039;&#039;&lt;br /&gt;
* {{bug|525013}} - investigate a more static build configuration of Firefox&lt;br /&gt;
** {{bug|532531}} - make binary components work on the Mac&lt;br /&gt;
** {{bug|532769}} - get a Linux static build going&lt;br /&gt;
** {{bug|532763}} - make binary components work on Linux&lt;br /&gt;
** {{bug|532771}} - get a Windows static build going&lt;br /&gt;
** {{bug|532765}} - make binary components work on Windows&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Results&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
There are no issues on Mac or Linux but Windows seems to build a dependency on firefox.exe into the components (see {{bug|532765}}).&lt;br /&gt;
&lt;br /&gt;
We definitely want to use _-mdynamic-no-pic_ on the Mac. At one point in time this resulted in a 50% startup boost when running from an external USB HD. The next day we were down to a more reasonable 15%. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Areas of work&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Results definitely need to be verified on all platforms. Need to fix our cold startup harness on the Mac to fully clear the OS caches ({{bug|532965}}).&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements&amp;diff=187814</id>
		<title>Firefox/Projects/Startup Time Improvements</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements&amp;diff=187814"/>
		<updated>2009-12-04T21:39:37Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Projects */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&#039;&#039;&#039;Project lead:&#039;&#039;&#039; Dietrich Ayala &amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Project members:&#039;&#039;&#039; Ryan Flint, Drew Willcoxon, David Dahl, Vlad Vukićević, Taras Glek, Joel Reymont, Ben Hsieh&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Investigate areas for improving startup time of the Mozilla platform, find &amp;amp; fix issues that help Fennec and WinCE.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bugs:&#039;&#039;&#039;&lt;br /&gt;
* [http://tinyurl.com/ygbnzmd Open] (identified by &amp;quot;[ts]&amp;quot; in the whiteboard field)&lt;br /&gt;
* [http://tinyurl.com/yjp8d6w Fixed]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Results&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See results in the [http://people.mozilla.org/~dietrich/snapshot/ Performance Snapshot].&lt;br /&gt;
&lt;br /&gt;
= Projects =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Areas of Work:&#039;&#039;&#039;&lt;br /&gt;
* minification&lt;br /&gt;
** {{bug|524858}} - minify js&lt;br /&gt;
** {{bug|513132}} - minify css&lt;br /&gt;
** {{bug|523479}} - minify extension&#039;s contents&lt;br /&gt;
* file combining&lt;br /&gt;
** {{bug|507101}} - combining js components&lt;br /&gt;
** {{bug|509755}} - put modules into a jar&lt;br /&gt;
* {{bug|FILEME}} - [https://bugzilla.mozilla.org/show_bug.cgi?id=279839#c29 string pool for jsxpcom]&lt;br /&gt;
* taking advantage of tracing&lt;br /&gt;
** figure out where we&#039;re not tracing in the startup log&lt;br /&gt;
** traceviz ({{bug|497999}})&lt;br /&gt;
* [[Firefox/Projects/Startup_Time_Improvements/Static_Build|static build]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Measurement &amp;amp; Testing&#039;&#039;&#039;&lt;br /&gt;
* cold startup testing&lt;br /&gt;
** &amp;lt;strike&amp;gt;{{bug|510587}} - mac and linux&amp;lt;/strike&amp;gt;&lt;br /&gt;
** {{bug|522807}} - windows&lt;br /&gt;
* dirty profile testing&lt;br /&gt;
** &amp;lt;strike&amp;gt;{{bug|414660}} - infrastructure &amp;amp; places&amp;lt;/strike&amp;gt;&lt;br /&gt;
** {{bug|515540}} - dirty+cold startup&lt;br /&gt;
** {{bug|527596}} - dirty Tp (teehee)&lt;br /&gt;
** {{bug|FILEME}} - test an all-dirty profile&lt;br /&gt;
** {{bug|FILEME}} - other dirty profiles&lt;br /&gt;
* micro-benchmarking&lt;br /&gt;
** {{bug|523146}} - test framework&lt;br /&gt;
** {{bug|479528}} - for location bar&lt;br /&gt;
** {{bug|451607}} - for places UI&lt;br /&gt;
** {{bug|479528}} - for places SQL&lt;br /&gt;
** more, eg: test for opening the 80th tab&lt;br /&gt;
* built-in startup measurement ({{bug|522375}})&lt;br /&gt;
** user-runnable Ts script, paste into js console&lt;br /&gt;
** restarts browser, passing last known time&lt;br /&gt;
** loads data URI that reads startup time and prints it out&lt;br /&gt;
** record startup timestamp as a pref?&lt;br /&gt;
* timeline of the startup path (David, Vlad)&lt;br /&gt;
** Status: incomplete (held up on hangs, nspr changes)&lt;br /&gt;
** [https://wiki.mozilla.org/Firefox/Sprints/Startup_Time_Improvements/StartupPatchUsage#Quick_Start docs]&lt;br /&gt;
** {{bug|480735}} instrumentation&lt;br /&gt;
** {{bug|503605}} visualization ([http://mozilla.ddahl.com/startup/timeline-similie.html Simile timeline], [http://people.mozilla.org/~dietrich/ddahl_sample_output.txt raw log])&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Docs:&#039;&#039;&#039;&lt;br /&gt;
* write best practices recommendation&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inactive Projects&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Mine the Ts DTrace viz/logs (Drew)&lt;br /&gt;
** Status: complete, moved on to filesystem operations below&lt;br /&gt;
** Results&lt;br /&gt;
*** cold startup is heavily I/O-bound. 90% of cold startup time is spent in page faults and other I/O syscalls, especially read, getattrlist, and stat.&lt;br /&gt;
*** majority of time spent after Firefox actually gets up and running is in XBL and CSS.&lt;br /&gt;
* Log and mine filesystem operations during startup (Ryan, Drew)&lt;br /&gt;
** Status: complete, bugs filed for egregious offenders&lt;br /&gt;
** Results&lt;br /&gt;
*** checking out Xperf and others for Windows work&lt;br /&gt;
*** investigating dtrace timing/FS cache issues on OS X&lt;br /&gt;
**** Instruments appears to have the same issues&lt;br /&gt;
*** Simple JS file exec script has yielded [https://bugzilla.mozilla.org/buglist.cgi?bug_id=504513 some results]&lt;br /&gt;
** References&lt;br /&gt;
*** [http://boomswaggerboom.wordpress.com/2009/06/24/firefox-for-mac-os-x-and-filesystem-related-system-calls/ Josh Aas&#039;s post on filesystem calls]&lt;br /&gt;
*** [http://blog.mozilla.com/tglek/2009/07/01/python-gdb-logging-file-io/ Taras&#039; post] on using GDB for logging&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/IO_Scratchpad]]&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/adw_notes|Drew&#039;s notes]]&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/joelr_notes|Joel&#039;s notes]]&lt;br /&gt;
* Find dead code with JSHydra (David Dahl)&lt;br /&gt;
** Status: incomplete, needs tuning and file bugs on dead code found&lt;br /&gt;
** {{bug|506128}} - run jshydra to find js functions that have no callers&lt;br /&gt;
* JSHydra continuous testing&lt;br /&gt;
** possible test scenarios&lt;br /&gt;
*** ending semicolon bug (XXX)&lt;br /&gt;
*** dead code finder&lt;br /&gt;
&lt;br /&gt;
=Status Updates=&lt;br /&gt;
&lt;br /&gt;
* [http://autonome.wordpress.com/2009/10/02/firefox-startup-performance-weekly-summary-4/ 10/2/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/26/firefox-startup-performance-weekly-summary-3/ 9/26/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/18/firefox-startup-performance-weekly-summary-2/ 9/18/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/06/firefox-startup-performance-weekly-summary/ 9/6/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/29/firefox-startup-performance-weekly-roundup/ 8/29/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/22/weekly-firefox-startup-performance-roundup-2/ 8/22/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/18/firefox-performance-the-dont-touch-the-damn-disk-edition/ 8/18/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/08/firefox-startup-performance/ 8/8/09]&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&lt;br /&gt;
;Meta bugs&lt;br /&gt;
* {{bug|459117}} Fennec performance meta bug&lt;br /&gt;
* {{bug|447581}} Startup meta bug&lt;br /&gt;
* {{bug|479078}} Startup research meta bug&lt;br /&gt;
* {{bug|7251}} very old startup meta bug&lt;br /&gt;
&lt;br /&gt;
* Vlad&#039;s blog posts&lt;br /&gt;
** [http://blog.vlad1.com/2009/06/17/firefox-startup-wrangling/ Vlad&#039;s June posting on startup work]&lt;br /&gt;
** Vlad&#039;s July posts:&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/27/startup-part-1/ 1]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/27/startup-again/ 2 - fs cache]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/28/startup-again-2/ 3 - event processing]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/28/measuring-startup/ 4 - measuring startup] &lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/29/startup-again-3/ 5 iosnoop]&lt;br /&gt;
&lt;br /&gt;
* zpao&#039;s JS treemap visualizations&lt;br /&gt;
** [http://playground.zpao.com/dtrace_treemaps2/ newer]&lt;br /&gt;
** [http://playground.zpao.com/dtrace_treemaps/ older]&lt;br /&gt;
&lt;br /&gt;
* Taras&#039; Fennec Startup Work&lt;br /&gt;
** {{bug|459117}} &amp;quot;make fennec faster&amp;quot;, mostly startup bugs&lt;br /&gt;
** [http://people.mozilla.com/~tglek/fennec/startup.txt startup log]&lt;br /&gt;
** {{bug|470116}} various timing scripts&lt;br /&gt;
&lt;br /&gt;
* [[Performance:Home_Page]]&lt;br /&gt;
&lt;br /&gt;
==Tips, Tools==&lt;br /&gt;
&lt;br /&gt;
* Cold startup&lt;br /&gt;
** [http://aegisknight.org/2009/04/flushing-disk-cache/ Flushing Windows&#039; disk cache]&lt;br /&gt;
** [http://tuvix.apple.com/DOCUMENTATION/Darwin/Reference/ManPages/man8/purge.8.html Flushing Mac OS X&#039;s disk cache]&lt;br /&gt;
** [[Firefox/Projects/Startup_Time_Improvements_Notes]]: Vlad&#039;s emails about cold startup, including Linux (maybe move this info to this page)&lt;br /&gt;
&lt;br /&gt;
* Windows Prefetch/Superfetch&lt;br /&gt;
** [http://en.wikipedia.org/wiki/Prefetcher XP Prefetch wiki]&lt;br /&gt;
** [http://en.wikipedia.org/wiki/Windows_Vista_I/O_technologies#SuperFetch Vista/Win7 SuperFetch wiki]&lt;br /&gt;
** [http://members.rushmore.com/~jsky/id37.html useful Pre/SuperFetch overview]&lt;br /&gt;
** [http://jessekornblum.com/presentations/dodcc08-2.html Presentation slides on the guts of Pref/SuperFetch by military forensic analyst]&lt;br /&gt;
*** Prefetch&lt;br /&gt;
**** Profile for each application: List of DLLs used, Run count, Time stamps&lt;br /&gt;
**** Prefetch files stored in %SystemRoot%\Prefetch: .pf extension, Up to 128 are kept&lt;br /&gt;
**** Can tell if same app run from multiple locations&lt;br /&gt;
*** SuperFetch&lt;br /&gt;
**** turn off: net stop sysmain&lt;br /&gt;
**** AG*.db files, contain &amp;quot;scenarios&amp;quot; for preloading&lt;br /&gt;
** [http://technet.microsoft.com/en-us/magazine/2007.03.vistakernel.aspx Technet article on Vista mem mgmnt]&lt;br /&gt;
** [http://www.howtogeek.com/howto/windows-vista/change-superfetch-to-only-cache-system-boot-files-in-vista/ registry keys for toggling SuperFetch]&lt;br /&gt;
&lt;br /&gt;
* DTrace&lt;br /&gt;
** [https://wiki.mozilla.org/Performance/Optimizing_JavaScript_with_DTrace nuts and bolts how-to for getting dtrace running with mozilla]&lt;br /&gt;
** [http://www.opensolaris.org/os/project/mozilla-dtrace/ project overview of integrating dtrace with mozilla]&lt;br /&gt;
** [http://www.opensolaris.org/os/community/dtrace/ dtrace community page, lots of links]&lt;br /&gt;
** [http://www.sun.com/bigadmin/content/dtrace/ dtrace homepage? not as useful as previous link]&lt;br /&gt;
** [http://wikis.sun.com/display/DTrace/Introduction intro from dtrace guidebook, really useful but not mozilla/js-specific]&lt;br /&gt;
** [http://blogs.sun.com/jmr/entry/dtrace_mozilla_rfe_javascript_tracing brief descriptions of the javascript* probes]&lt;br /&gt;
** [http://blog.mozilla.com/dmandelin/2008/02/14/dtrace-c-mysteries-solved/ David Mandelin&#039;s notes on tracing C++ code]&lt;br /&gt;
&lt;br /&gt;
* comparing dynamic linking time between firefox and safari on mac&lt;br /&gt;
** DYLD_PRINT_STATISTICS=YES /Applications/Firefox.app/Contents/MacOS/firefox-bin&lt;br /&gt;
** DYLD_PRINT_STATISTICS=YES open -a Safari&lt;br /&gt;
&lt;br /&gt;
==Fastload==&lt;br /&gt;
* why does js_Execute take so long for fastloaded components?&lt;br /&gt;
* [http://groups.google.com/group/mozilla.dev.platform/browse_thread/thread/42c0e9df84b935fe what is fastload?]&lt;br /&gt;
* [http://kb.mozillazine.org/Nglayout.debug.disable_xul_fastload fastload pref docs]&lt;br /&gt;
&lt;br /&gt;
==Measuring Ts==&lt;br /&gt;
&lt;br /&gt;
We&#039;ve been using a method Vlad blogged about [http://blog.vlad1.com/2009/07/28/measuring-startup/ here]. The steps are below.&lt;br /&gt;
&lt;br /&gt;
# save [http://people.mozilla.com/~vladimir/misc/startup.html this html file] somewhere locally&lt;br /&gt;
# create a new profile, run Firefox with it at least once, so all files are created, etc&lt;br /&gt;
# execute this command, with your profile name substituted, and invoking firefox in a way appropriate for your platform:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
./firefox -P YourProfileName -no-remote file:///..../startup.html#`python -c &#039;import time; print int(time.time() * 1000);&#039;`&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is specific to Mac OSX and is required to evict Firefox code pages from memory and clear the Unified Buffer Cache (UBC). &amp;lt;code&amp;gt;purge&amp;lt;/code&amp;gt; does NOT do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
FF=/tmp/firefox&lt;br /&gt;
&lt;br /&gt;
mkdir $FF &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
umount $FF &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
mount_hfs /dev/disk1s2 $FF&lt;br /&gt;
&lt;br /&gt;
$FF/Minefield$*.app/Contents/MacOS/firefox-bin -no-remote -foreground file://$FF/startup.html#`python -c &#039;import time; print int(time.time() * 1000);&#039;`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This assumes that your removable media is at /dev/disk1s2. &lt;br /&gt;
&lt;br /&gt;
First, mount you external USB HD normally and use &amp;lt;code&amp;gt;df&amp;lt;/code&amp;gt; to see what device is being used. Then eject the drive using &amp;lt;code&amp;gt;diskutil umount /Volumes/YourDrive&amp;lt;/code&amp;gt; and you are set. &lt;br /&gt;
&lt;br /&gt;
Do not eject the device using the Finder as that will not make it available at /dev/disk1s2 or wherever it was.&lt;br /&gt;
&lt;br /&gt;
==Test Coverage==&lt;br /&gt;
&lt;br /&gt;
This is an index of Firefox startup scenarios which need automated test coverage.&lt;br /&gt;
&lt;br /&gt;
TODO:&lt;br /&gt;
* groups: chrome, content, extensions, labs, other?&lt;br /&gt;
* mark which need no-chrome testing&lt;br /&gt;
&lt;br /&gt;
{| border=solid black 1px&lt;br /&gt;
| test || warm start || cold start || notes&lt;br /&gt;
|-&lt;br /&gt;
| empty profile ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||&lt;br /&gt;
|-&lt;br /&gt;
| everything dirty || || || {{bug|515540}}&lt;br /&gt;
|-&lt;br /&gt;
| min places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || informed by places-stats, {{bug|515540}}&lt;br /&gt;
|-&lt;br /&gt;
| med places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || ditto&lt;br /&gt;
|-&lt;br /&gt;
| max places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || ditto&lt;br /&gt;
|-&lt;br /&gt;
| med session || || || informed by test pilot data&lt;br /&gt;
|-&lt;br /&gt;
| max session || || || ditto&lt;br /&gt;
|-&lt;br /&gt;
| downloads || || ||&lt;br /&gt;
|-&lt;br /&gt;
| url-classifier data || || || data is fully downloaded, should test page-load for a match and no match&lt;br /&gt;
|-&lt;br /&gt;
| form history|| || ||&lt;br /&gt;
|-&lt;br /&gt;
| passwords || || ||&lt;br /&gt;
|-&lt;br /&gt;
| plugins || || ||&lt;br /&gt;
|-&lt;br /&gt;
| content preferences || || ||&lt;br /&gt;
|-&lt;br /&gt;
| extensions || || || top 5?&lt;br /&gt;
|-&lt;br /&gt;
| extension update || || ||&lt;br /&gt;
|-&lt;br /&gt;
| application update || || ||&lt;br /&gt;
|-&lt;br /&gt;
| persona applied || || ||&lt;br /&gt;
|-&lt;br /&gt;
| weave || || ||&lt;br /&gt;
|-&lt;br /&gt;
| jetpack || || ||&lt;br /&gt;
|-&lt;br /&gt;
| ubiquity || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page links are visited || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page has microformats || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page is ssl || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page has plugin || || ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements&amp;diff=187806</id>
		<title>Firefox/Projects/Startup Time Improvements</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements&amp;diff=187806"/>
		<updated>2009-12-04T21:13:42Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Projects */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&#039;&#039;&#039;Project lead:&#039;&#039;&#039; Dietrich Ayala &amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Project members:&#039;&#039;&#039; Ryan Flint, Drew Willcoxon, David Dahl, Vlad Vukićević, Taras Glek, Joel Reymont, Ben Hsieh&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Investigate areas for improving startup time of the Mozilla platform, find &amp;amp; fix issues that help Fennec and WinCE.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bugs:&#039;&#039;&#039;&lt;br /&gt;
* [http://tinyurl.com/ygbnzmd Open] (identified by &amp;quot;[ts]&amp;quot; in the whiteboard field)&lt;br /&gt;
* [http://tinyurl.com/yjp8d6w Fixed]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Results&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See results in the [http://people.mozilla.org/~dietrich/snapshot/ Performance Snapshot].&lt;br /&gt;
&lt;br /&gt;
= Projects =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Areas of Work:&#039;&#039;&#039;&lt;br /&gt;
* minification&lt;br /&gt;
** {{bug|524858}} - minify js&lt;br /&gt;
** {{bug|513132}} - minify css&lt;br /&gt;
** {{bug|523479}} - minify extension&#039;s contents&lt;br /&gt;
* file combining&lt;br /&gt;
** {{bug|507101}} - combining js components&lt;br /&gt;
** {{bug|509755}} - put modules into a jar&lt;br /&gt;
* {{bug|FILEME}} - [https://bugzilla.mozilla.org/show_bug.cgi?id=279839#c29 string pool for jsxpcom]&lt;br /&gt;
* taking advantage of tracing&lt;br /&gt;
** figure out where we&#039;re not tracing in the startup log&lt;br /&gt;
** traceviz ({{bug|497999}})&lt;br /&gt;
* [[Firefox/Projects/Startup_Time_Improvements/StaticBuild|static build]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Measurement &amp;amp; Testing&#039;&#039;&#039;&lt;br /&gt;
* cold startup testing&lt;br /&gt;
** &amp;lt;strike&amp;gt;{{bug|510587}} - mac and linux&amp;lt;/strike&amp;gt;&lt;br /&gt;
** {{bug|522807}} - windows&lt;br /&gt;
* dirty profile testing&lt;br /&gt;
** &amp;lt;strike&amp;gt;{{bug|414660}} - infrastructure &amp;amp; places&amp;lt;/strike&amp;gt;&lt;br /&gt;
** {{bug|515540}} - dirty+cold startup&lt;br /&gt;
** {{bug|527596}} - dirty Tp (teehee)&lt;br /&gt;
** {{bug|FILEME}} - test an all-dirty profile&lt;br /&gt;
** {{bug|FILEME}} - other dirty profiles&lt;br /&gt;
* micro-benchmarking&lt;br /&gt;
** {{bug|523146}} - test framework&lt;br /&gt;
** {{bug|479528}} - for location bar&lt;br /&gt;
** {{bug|451607}} - for places UI&lt;br /&gt;
** {{bug|479528}} - for places SQL&lt;br /&gt;
** more, eg: test for opening the 80th tab&lt;br /&gt;
* built-in startup measurement ({{bug|522375}})&lt;br /&gt;
** user-runnable Ts script, paste into js console&lt;br /&gt;
** restarts browser, passing last known time&lt;br /&gt;
** loads data URI that reads startup time and prints it out&lt;br /&gt;
** record startup timestamp as a pref?&lt;br /&gt;
* timeline of the startup path (David, Vlad)&lt;br /&gt;
** Status: incomplete (held up on hangs, nspr changes)&lt;br /&gt;
** [https://wiki.mozilla.org/Firefox/Sprints/Startup_Time_Improvements/StartupPatchUsage#Quick_Start docs]&lt;br /&gt;
** {{bug|480735}} instrumentation&lt;br /&gt;
** {{bug|503605}} visualization ([http://mozilla.ddahl.com/startup/timeline-similie.html Simile timeline], [http://people.mozilla.org/~dietrich/ddahl_sample_output.txt raw log])&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Docs:&#039;&#039;&#039;&lt;br /&gt;
* write best practices recommendation&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inactive Projects&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Mine the Ts DTrace viz/logs (Drew)&lt;br /&gt;
** Status: complete, moved on to filesystem operations below&lt;br /&gt;
** Results&lt;br /&gt;
*** cold startup is heavily I/O-bound. 90% of cold startup time is spent in page faults and other I/O syscalls, especially read, getattrlist, and stat.&lt;br /&gt;
*** majority of time spent after Firefox actually gets up and running is in XBL and CSS.&lt;br /&gt;
* Log and mine filesystem operations during startup (Ryan, Drew)&lt;br /&gt;
** Status: complete, bugs filed for egregious offenders&lt;br /&gt;
** Results&lt;br /&gt;
*** checking out Xperf and others for Windows work&lt;br /&gt;
*** investigating dtrace timing/FS cache issues on OS X&lt;br /&gt;
**** Instruments appears to have the same issues&lt;br /&gt;
*** Simple JS file exec script has yielded [https://bugzilla.mozilla.org/buglist.cgi?bug_id=504513 some results]&lt;br /&gt;
** References&lt;br /&gt;
*** [http://boomswaggerboom.wordpress.com/2009/06/24/firefox-for-mac-os-x-and-filesystem-related-system-calls/ Josh Aas&#039;s post on filesystem calls]&lt;br /&gt;
*** [http://blog.mozilla.com/tglek/2009/07/01/python-gdb-logging-file-io/ Taras&#039; post] on using GDB for logging&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/IO_Scratchpad]]&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/adw_notes|Drew&#039;s notes]]&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/joelr_notes|Joel&#039;s notes]]&lt;br /&gt;
* Find dead code with JSHydra (David Dahl)&lt;br /&gt;
** Status: incomplete, needs tuning and file bugs on dead code found&lt;br /&gt;
** {{bug|506128}} - run jshydra to find js functions that have no callers&lt;br /&gt;
* JSHydra continuous testing&lt;br /&gt;
** possible test scenarios&lt;br /&gt;
*** ending semicolon bug (XXX)&lt;br /&gt;
*** dead code finder&lt;br /&gt;
&lt;br /&gt;
=Status Updates=&lt;br /&gt;
&lt;br /&gt;
* [http://autonome.wordpress.com/2009/10/02/firefox-startup-performance-weekly-summary-4/ 10/2/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/26/firefox-startup-performance-weekly-summary-3/ 9/26/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/18/firefox-startup-performance-weekly-summary-2/ 9/18/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/06/firefox-startup-performance-weekly-summary/ 9/6/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/29/firefox-startup-performance-weekly-roundup/ 8/29/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/22/weekly-firefox-startup-performance-roundup-2/ 8/22/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/18/firefox-performance-the-dont-touch-the-damn-disk-edition/ 8/18/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/08/firefox-startup-performance/ 8/8/09]&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&lt;br /&gt;
;Meta bugs&lt;br /&gt;
* {{bug|459117}} Fennec performance meta bug&lt;br /&gt;
* {{bug|447581}} Startup meta bug&lt;br /&gt;
* {{bug|479078}} Startup research meta bug&lt;br /&gt;
* {{bug|7251}} very old startup meta bug&lt;br /&gt;
&lt;br /&gt;
* Vlad&#039;s blog posts&lt;br /&gt;
** [http://blog.vlad1.com/2009/06/17/firefox-startup-wrangling/ Vlad&#039;s June posting on startup work]&lt;br /&gt;
** Vlad&#039;s July posts:&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/27/startup-part-1/ 1]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/27/startup-again/ 2 - fs cache]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/28/startup-again-2/ 3 - event processing]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/28/measuring-startup/ 4 - measuring startup] &lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/29/startup-again-3/ 5 iosnoop]&lt;br /&gt;
&lt;br /&gt;
* zpao&#039;s JS treemap visualizations&lt;br /&gt;
** [http://playground.zpao.com/dtrace_treemaps2/ newer]&lt;br /&gt;
** [http://playground.zpao.com/dtrace_treemaps/ older]&lt;br /&gt;
&lt;br /&gt;
* Taras&#039; Fennec Startup Work&lt;br /&gt;
** {{bug|459117}} &amp;quot;make fennec faster&amp;quot;, mostly startup bugs&lt;br /&gt;
** [http://people.mozilla.com/~tglek/fennec/startup.txt startup log]&lt;br /&gt;
** {{bug|470116}} various timing scripts&lt;br /&gt;
&lt;br /&gt;
* [[Performance:Home_Page]]&lt;br /&gt;
&lt;br /&gt;
==Tips, Tools==&lt;br /&gt;
&lt;br /&gt;
* Cold startup&lt;br /&gt;
** [http://aegisknight.org/2009/04/flushing-disk-cache/ Flushing Windows&#039; disk cache]&lt;br /&gt;
** [http://tuvix.apple.com/DOCUMENTATION/Darwin/Reference/ManPages/man8/purge.8.html Flushing Mac OS X&#039;s disk cache]&lt;br /&gt;
** [[Firefox/Projects/Startup_Time_Improvements_Notes]]: Vlad&#039;s emails about cold startup, including Linux (maybe move this info to this page)&lt;br /&gt;
&lt;br /&gt;
* Windows Prefetch/Superfetch&lt;br /&gt;
** [http://en.wikipedia.org/wiki/Prefetcher XP Prefetch wiki]&lt;br /&gt;
** [http://en.wikipedia.org/wiki/Windows_Vista_I/O_technologies#SuperFetch Vista/Win7 SuperFetch wiki]&lt;br /&gt;
** [http://members.rushmore.com/~jsky/id37.html useful Pre/SuperFetch overview]&lt;br /&gt;
** [http://jessekornblum.com/presentations/dodcc08-2.html Presentation slides on the guts of Pref/SuperFetch by military forensic analyst]&lt;br /&gt;
*** Prefetch&lt;br /&gt;
**** Profile for each application: List of DLLs used, Run count, Time stamps&lt;br /&gt;
**** Prefetch files stored in %SystemRoot%\Prefetch: .pf extension, Up to 128 are kept&lt;br /&gt;
**** Can tell if same app run from multiple locations&lt;br /&gt;
*** SuperFetch&lt;br /&gt;
**** turn off: net stop sysmain&lt;br /&gt;
**** AG*.db files, contain &amp;quot;scenarios&amp;quot; for preloading&lt;br /&gt;
** [http://technet.microsoft.com/en-us/magazine/2007.03.vistakernel.aspx Technet article on Vista mem mgmnt]&lt;br /&gt;
** [http://www.howtogeek.com/howto/windows-vista/change-superfetch-to-only-cache-system-boot-files-in-vista/ registry keys for toggling SuperFetch]&lt;br /&gt;
&lt;br /&gt;
* DTrace&lt;br /&gt;
** [https://wiki.mozilla.org/Performance/Optimizing_JavaScript_with_DTrace nuts and bolts how-to for getting dtrace running with mozilla]&lt;br /&gt;
** [http://www.opensolaris.org/os/project/mozilla-dtrace/ project overview of integrating dtrace with mozilla]&lt;br /&gt;
** [http://www.opensolaris.org/os/community/dtrace/ dtrace community page, lots of links]&lt;br /&gt;
** [http://www.sun.com/bigadmin/content/dtrace/ dtrace homepage? not as useful as previous link]&lt;br /&gt;
** [http://wikis.sun.com/display/DTrace/Introduction intro from dtrace guidebook, really useful but not mozilla/js-specific]&lt;br /&gt;
** [http://blogs.sun.com/jmr/entry/dtrace_mozilla_rfe_javascript_tracing brief descriptions of the javascript* probes]&lt;br /&gt;
** [http://blog.mozilla.com/dmandelin/2008/02/14/dtrace-c-mysteries-solved/ David Mandelin&#039;s notes on tracing C++ code]&lt;br /&gt;
&lt;br /&gt;
* comparing dynamic linking time between firefox and safari on mac&lt;br /&gt;
** DYLD_PRINT_STATISTICS=YES /Applications/Firefox.app/Contents/MacOS/firefox-bin&lt;br /&gt;
** DYLD_PRINT_STATISTICS=YES open -a Safari&lt;br /&gt;
&lt;br /&gt;
==Fastload==&lt;br /&gt;
* why does js_Execute take so long for fastloaded components?&lt;br /&gt;
* [http://groups.google.com/group/mozilla.dev.platform/browse_thread/thread/42c0e9df84b935fe what is fastload?]&lt;br /&gt;
* [http://kb.mozillazine.org/Nglayout.debug.disable_xul_fastload fastload pref docs]&lt;br /&gt;
&lt;br /&gt;
==Measuring Ts==&lt;br /&gt;
&lt;br /&gt;
We&#039;ve been using a method Vlad blogged about [http://blog.vlad1.com/2009/07/28/measuring-startup/ here]. The steps are below.&lt;br /&gt;
&lt;br /&gt;
# save [http://people.mozilla.com/~vladimir/misc/startup.html this html file] somewhere locally&lt;br /&gt;
# create a new profile, run Firefox with it at least once, so all files are created, etc&lt;br /&gt;
# execute this command, with your profile name substituted, and invoking firefox in a way appropriate for your platform:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
./firefox -P YourProfileName -no-remote file:///..../startup.html#`python -c &#039;import time; print int(time.time() * 1000);&#039;`&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is specific to Mac OSX and is required to evict Firefox code pages from memory and clear the Unified Buffer Cache (UBC). &amp;lt;code&amp;gt;purge&amp;lt;/code&amp;gt; does NOT do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
FF=/tmp/firefox&lt;br /&gt;
&lt;br /&gt;
mkdir $FF &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
umount $FF &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
mount_hfs /dev/disk1s2 $FF&lt;br /&gt;
&lt;br /&gt;
$FF/Minefield$*.app/Contents/MacOS/firefox-bin -no-remote -foreground file://$FF/startup.html#`python -c &#039;import time; print int(time.time() * 1000);&#039;`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This assumes that your removable media is at /dev/disk1s2. &lt;br /&gt;
&lt;br /&gt;
First, mount you external USB HD normally and use &amp;lt;code&amp;gt;df&amp;lt;/code&amp;gt; to see what device is being used. Then eject the drive using &amp;lt;code&amp;gt;diskutil umount /Volumes/YourDrive&amp;lt;/code&amp;gt; and you are set. &lt;br /&gt;
&lt;br /&gt;
Do not eject the device using the Finder as that will not make it available at /dev/disk1s2 or wherever it was.&lt;br /&gt;
&lt;br /&gt;
==Test Coverage==&lt;br /&gt;
&lt;br /&gt;
This is an index of Firefox startup scenarios which need automated test coverage.&lt;br /&gt;
&lt;br /&gt;
TODO:&lt;br /&gt;
* groups: chrome, content, extensions, labs, other?&lt;br /&gt;
* mark which need no-chrome testing&lt;br /&gt;
&lt;br /&gt;
{| border=solid black 1px&lt;br /&gt;
| test || warm start || cold start || notes&lt;br /&gt;
|-&lt;br /&gt;
| empty profile ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||&lt;br /&gt;
|-&lt;br /&gt;
| everything dirty || || || {{bug|515540}}&lt;br /&gt;
|-&lt;br /&gt;
| min places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || informed by places-stats, {{bug|515540}}&lt;br /&gt;
|-&lt;br /&gt;
| med places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || ditto&lt;br /&gt;
|-&lt;br /&gt;
| max places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || ditto&lt;br /&gt;
|-&lt;br /&gt;
| med session || || || informed by test pilot data&lt;br /&gt;
|-&lt;br /&gt;
| max session || || || ditto&lt;br /&gt;
|-&lt;br /&gt;
| downloads || || ||&lt;br /&gt;
|-&lt;br /&gt;
| url-classifier data || || || data is fully downloaded, should test page-load for a match and no match&lt;br /&gt;
|-&lt;br /&gt;
| form history|| || ||&lt;br /&gt;
|-&lt;br /&gt;
| passwords || || ||&lt;br /&gt;
|-&lt;br /&gt;
| plugins || || ||&lt;br /&gt;
|-&lt;br /&gt;
| content preferences || || ||&lt;br /&gt;
|-&lt;br /&gt;
| extensions || || || top 5?&lt;br /&gt;
|-&lt;br /&gt;
| extension update || || ||&lt;br /&gt;
|-&lt;br /&gt;
| application update || || ||&lt;br /&gt;
|-&lt;br /&gt;
| persona applied || || ||&lt;br /&gt;
|-&lt;br /&gt;
| weave || || ||&lt;br /&gt;
|-&lt;br /&gt;
| jetpack || || ||&lt;br /&gt;
|-&lt;br /&gt;
| ubiquity || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page links are visited || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page has microformats || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page is ssl || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page has plugin || || ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements&amp;diff=186958</id>
		<title>Firefox/Projects/Startup Time Improvements</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements&amp;diff=186958"/>
		<updated>2009-12-01T19:38:54Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Measuring Ts */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&#039;&#039;&#039;Project lead:&#039;&#039;&#039; Dietrich Ayala &amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Project members:&#039;&#039;&#039; Ryan Flint, Drew Willcoxon, David Dahl, Vlad Vukićević, Taras Glek, Joel Reymont, Ben Hsieh&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Investigate areas for improving startup time of the Mozilla platform, find &amp;amp; fix issues that help Fennec and WinCE.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bugs:&#039;&#039;&#039;&lt;br /&gt;
* [http://tinyurl.com/ygbnzmd Open] (identified by &amp;quot;[ts]&amp;quot; in the whiteboard field)&lt;br /&gt;
* [http://tinyurl.com/yjp8d6w Fixed]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Results&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See results in the [http://people.mozilla.org/~dietrich/snapshot/ Performance Snapshot].&lt;br /&gt;
&lt;br /&gt;
= Projects =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Areas of Work:&#039;&#039;&#039;&lt;br /&gt;
* minification&lt;br /&gt;
** {{bug|524858}} - minify js&lt;br /&gt;
** {{bug|513132}} - minify css&lt;br /&gt;
** {{bug|523479}} - minify extension&#039;s contents&lt;br /&gt;
* file combining&lt;br /&gt;
** {{bug|507101}} - combining js components&lt;br /&gt;
** {{bug|509755}} - put modules into a jar&lt;br /&gt;
* {{bug|FILEME}} - [https://bugzilla.mozilla.org/show_bug.cgi?id=279839#c29 string pool for jsxpcom]&lt;br /&gt;
* taking advantage of tracing&lt;br /&gt;
** figure out where we&#039;re not tracing in the startup log&lt;br /&gt;
** traceviz ({{bug|497999}})&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Measurement &amp;amp; Testing&#039;&#039;&#039;&lt;br /&gt;
* cold startup testing&lt;br /&gt;
** &amp;lt;strike&amp;gt;{{bug|510587}} - mac and linux&amp;lt;/strike&amp;gt;&lt;br /&gt;
** {{bug|522807}} - windows&lt;br /&gt;
* dirty profile testing&lt;br /&gt;
** &amp;lt;strike&amp;gt;{{bug|414660}} - infrastructure &amp;amp; places&amp;lt;/strike&amp;gt;&lt;br /&gt;
** {{bug|515540}} - dirty+cold startup&lt;br /&gt;
** {{bug|527596}} - dirty Tp (teehee)&lt;br /&gt;
** {{bug|FILEME}} - test an all-dirty profile&lt;br /&gt;
** {{bug|FILEME}} - other dirty profiles&lt;br /&gt;
* micro-benchmarking&lt;br /&gt;
** {{bug|523146}} - test framework&lt;br /&gt;
** {{bug|479528}} - for location bar&lt;br /&gt;
** {{bug|451607}} - for places UI&lt;br /&gt;
** {{bug|479528}} - for places SQL&lt;br /&gt;
** more, eg: test for opening the 80th tab&lt;br /&gt;
* built-in startup measurement ({{bug|522375}})&lt;br /&gt;
** user-runnable Ts script, paste into js console&lt;br /&gt;
** restarts browser, passing last known time&lt;br /&gt;
** loads data URI that reads startup time and prints it out&lt;br /&gt;
** record startup timestamp as a pref?&lt;br /&gt;
* timeline of the startup path (David, Vlad)&lt;br /&gt;
** Status: incomplete (held up on hangs, nspr changes)&lt;br /&gt;
** [https://wiki.mozilla.org/Firefox/Sprints/Startup_Time_Improvements/StartupPatchUsage#Quick_Start docs]&lt;br /&gt;
** {{bug|480735}} instrumentation&lt;br /&gt;
** {{bug|503605}} visualization ([http://mozilla.ddahl.com/startup/timeline-similie.html Simile timeline], [http://people.mozilla.org/~dietrich/ddahl_sample_output.txt raw log])&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Docs:&#039;&#039;&#039;&lt;br /&gt;
* write best practices recommendation&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inactive Projects&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Mine the Ts DTrace viz/logs (Drew)&lt;br /&gt;
** Status: complete, moved on to filesystem operations below&lt;br /&gt;
** Results&lt;br /&gt;
*** cold startup is heavily I/O-bound. 90% of cold startup time is spent in page faults and other I/O syscalls, especially read, getattrlist, and stat.&lt;br /&gt;
*** majority of time spent after Firefox actually gets up and running is in XBL and CSS.&lt;br /&gt;
* Log and mine filesystem operations during startup (Ryan, Drew)&lt;br /&gt;
** Status: complete, bugs filed for egregious offenders&lt;br /&gt;
** Results&lt;br /&gt;
*** checking out Xperf and others for Windows work&lt;br /&gt;
*** investigating dtrace timing/FS cache issues on OS X&lt;br /&gt;
**** Instruments appears to have the same issues&lt;br /&gt;
*** Simple JS file exec script has yielded [https://bugzilla.mozilla.org/buglist.cgi?bug_id=504513 some results]&lt;br /&gt;
** References&lt;br /&gt;
*** [http://boomswaggerboom.wordpress.com/2009/06/24/firefox-for-mac-os-x-and-filesystem-related-system-calls/ Josh Aas&#039;s post on filesystem calls]&lt;br /&gt;
*** [http://blog.mozilla.com/tglek/2009/07/01/python-gdb-logging-file-io/ Taras&#039; post] on using GDB for logging&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/IO_Scratchpad]]&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/adw_notes|Drew&#039;s notes]]&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/joelr_notes|Joel&#039;s notes]]&lt;br /&gt;
* Find dead code with JSHydra (David Dahl)&lt;br /&gt;
** Status: incomplete, needs tuning and file bugs on dead code found&lt;br /&gt;
** {{bug|506128}} - run jshydra to find js functions that have no callers&lt;br /&gt;
* JSHydra continuous testing&lt;br /&gt;
** possible test scenarios&lt;br /&gt;
*** ending semicolon bug (XXX)&lt;br /&gt;
*** dead code finder&lt;br /&gt;
&lt;br /&gt;
=Status Updates=&lt;br /&gt;
&lt;br /&gt;
* [http://autonome.wordpress.com/2009/10/02/firefox-startup-performance-weekly-summary-4/ 10/2/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/26/firefox-startup-performance-weekly-summary-3/ 9/26/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/18/firefox-startup-performance-weekly-summary-2/ 9/18/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/06/firefox-startup-performance-weekly-summary/ 9/6/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/29/firefox-startup-performance-weekly-roundup/ 8/29/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/22/weekly-firefox-startup-performance-roundup-2/ 8/22/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/18/firefox-performance-the-dont-touch-the-damn-disk-edition/ 8/18/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/08/firefox-startup-performance/ 8/8/09]&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&lt;br /&gt;
;Meta bugs&lt;br /&gt;
* {{bug|459117}} Fennec performance meta bug&lt;br /&gt;
* {{bug|447581}} Startup meta bug&lt;br /&gt;
* {{bug|479078}} Startup research meta bug&lt;br /&gt;
* {{bug|7251}} very old startup meta bug&lt;br /&gt;
&lt;br /&gt;
* Vlad&#039;s blog posts&lt;br /&gt;
** [http://blog.vlad1.com/2009/06/17/firefox-startup-wrangling/ Vlad&#039;s June posting on startup work]&lt;br /&gt;
** Vlad&#039;s July posts:&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/27/startup-part-1/ 1]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/27/startup-again/ 2 - fs cache]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/28/startup-again-2/ 3 - event processing]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/28/measuring-startup/ 4 - measuring startup] &lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/29/startup-again-3/ 5 iosnoop]&lt;br /&gt;
&lt;br /&gt;
* zpao&#039;s JS treemap visualizations&lt;br /&gt;
** [http://playground.zpao.com/dtrace_treemaps2/ newer]&lt;br /&gt;
** [http://playground.zpao.com/dtrace_treemaps/ older]&lt;br /&gt;
&lt;br /&gt;
* Taras&#039; Fennec Startup Work&lt;br /&gt;
** {{bug|459117}} &amp;quot;make fennec faster&amp;quot;, mostly startup bugs&lt;br /&gt;
** [http://people.mozilla.com/~tglek/fennec/startup.txt startup log]&lt;br /&gt;
** {{bug|470116}} various timing scripts&lt;br /&gt;
&lt;br /&gt;
* [[Performance:Home_Page]]&lt;br /&gt;
&lt;br /&gt;
==Tips, Tools==&lt;br /&gt;
&lt;br /&gt;
* Cold startup&lt;br /&gt;
** [http://aegisknight.org/2009/04/flushing-disk-cache/ Flushing Windows&#039; disk cache]&lt;br /&gt;
** [http://tuvix.apple.com/DOCUMENTATION/Darwin/Reference/ManPages/man8/purge.8.html Flushing Mac OS X&#039;s disk cache]&lt;br /&gt;
** [[Firefox/Projects/Startup_Time_Improvements_Notes]]: Vlad&#039;s emails about cold startup, including Linux (maybe move this info to this page)&lt;br /&gt;
&lt;br /&gt;
* Windows Prefetch/Superfetch&lt;br /&gt;
** [http://en.wikipedia.org/wiki/Prefetcher XP Prefetch wiki]&lt;br /&gt;
** [http://en.wikipedia.org/wiki/Windows_Vista_I/O_technologies#SuperFetch Vista/Win7 SuperFetch wiki]&lt;br /&gt;
** [http://members.rushmore.com/~jsky/id37.html useful Pre/SuperFetch overview]&lt;br /&gt;
** [http://jessekornblum.com/presentations/dodcc08-2.html Presentation slides on the guts of Pref/SuperFetch by military forensic analyst]&lt;br /&gt;
*** Prefetch&lt;br /&gt;
**** Profile for each application: List of DLLs used, Run count, Time stamps&lt;br /&gt;
**** Prefetch files stored in %SystemRoot%\Prefetch: .pf extension, Up to 128 are kept&lt;br /&gt;
**** Can tell if same app run from multiple locations&lt;br /&gt;
*** SuperFetch&lt;br /&gt;
**** turn off: net stop sysmain&lt;br /&gt;
**** AG*.db files, contain &amp;quot;scenarios&amp;quot; for preloading&lt;br /&gt;
** [http://technet.microsoft.com/en-us/magazine/2007.03.vistakernel.aspx Technet article on Vista mem mgmnt]&lt;br /&gt;
** [http://www.howtogeek.com/howto/windows-vista/change-superfetch-to-only-cache-system-boot-files-in-vista/ registry keys for toggling SuperFetch]&lt;br /&gt;
&lt;br /&gt;
* DTrace&lt;br /&gt;
** [https://wiki.mozilla.org/Performance/Optimizing_JavaScript_with_DTrace nuts and bolts how-to for getting dtrace running with mozilla]&lt;br /&gt;
** [http://www.opensolaris.org/os/project/mozilla-dtrace/ project overview of integrating dtrace with mozilla]&lt;br /&gt;
** [http://www.opensolaris.org/os/community/dtrace/ dtrace community page, lots of links]&lt;br /&gt;
** [http://www.sun.com/bigadmin/content/dtrace/ dtrace homepage? not as useful as previous link]&lt;br /&gt;
** [http://wikis.sun.com/display/DTrace/Introduction intro from dtrace guidebook, really useful but not mozilla/js-specific]&lt;br /&gt;
** [http://blogs.sun.com/jmr/entry/dtrace_mozilla_rfe_javascript_tracing brief descriptions of the javascript* probes]&lt;br /&gt;
** [http://blog.mozilla.com/dmandelin/2008/02/14/dtrace-c-mysteries-solved/ David Mandelin&#039;s notes on tracing C++ code]&lt;br /&gt;
&lt;br /&gt;
* comparing dynamic linking time between firefox and safari on mac&lt;br /&gt;
** DYLD_PRINT_STATISTICS=YES /Applications/Firefox.app/Contents/MacOS/firefox-bin&lt;br /&gt;
** DYLD_PRINT_STATISTICS=YES open -a Safari&lt;br /&gt;
&lt;br /&gt;
==Fastload==&lt;br /&gt;
* why does js_Execute take so long for fastloaded components?&lt;br /&gt;
* [http://groups.google.com/group/mozilla.dev.platform/browse_thread/thread/42c0e9df84b935fe what is fastload?]&lt;br /&gt;
* [http://kb.mozillazine.org/Nglayout.debug.disable_xul_fastload fastload pref docs]&lt;br /&gt;
&lt;br /&gt;
==Measuring Ts==&lt;br /&gt;
&lt;br /&gt;
We&#039;ve been using a method Vlad blogged about [http://blog.vlad1.com/2009/07/28/measuring-startup/ here]. The steps are below.&lt;br /&gt;
&lt;br /&gt;
# save [http://people.mozilla.com/~vladimir/misc/startup.html this html file] somewhere locally&lt;br /&gt;
# create a new profile, run Firefox with it at least once, so all files are created, etc&lt;br /&gt;
# execute this command, with your profile name substituted, and invoking firefox in a way appropriate for your platform:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
./firefox -P YourProfileName -no-remote file:///..../startup.html#`python -c &#039;import time; print int(time.time() * 1000);&#039;`&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is specific to Mac OSX and is required to evict Firefox code pages from memory and clear the Unified Buffer Cache (UBC). &amp;lt;code&amp;gt;purge&amp;lt;/code&amp;gt; does NOT do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
FF=/tmp/firefox&lt;br /&gt;
&lt;br /&gt;
mkdir $FF &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
umount $FF &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
mount_hfs /dev/disk1s2 $FF&lt;br /&gt;
&lt;br /&gt;
$FF/Minefield$*.app/Contents/MacOS/firefox-bin -no-remote -foreground file://$FF/startup.html#`python -c &#039;import time; print int(time.time() * 1000);&#039;`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This assumes that your removable media is at /dev/disk1s2. &lt;br /&gt;
&lt;br /&gt;
First, mount you external USB HD normally and use &amp;lt;code&amp;gt;df&amp;lt;/code&amp;gt; to see what device is being used. Then eject the drive using &amp;lt;code&amp;gt;diskutil umount /Volumes/YourDrive&amp;lt;/code&amp;gt; and you are set. &lt;br /&gt;
&lt;br /&gt;
Do not eject the device using the Finder as that will not make it available at /dev/disk1s2 or wherever it was.&lt;br /&gt;
&lt;br /&gt;
==Test Coverage==&lt;br /&gt;
&lt;br /&gt;
This is an index of Firefox startup scenarios which need automated test coverage.&lt;br /&gt;
&lt;br /&gt;
TODO:&lt;br /&gt;
* groups: chrome, content, extensions, labs, other?&lt;br /&gt;
* mark which need no-chrome testing&lt;br /&gt;
&lt;br /&gt;
{| border=solid black 1px&lt;br /&gt;
| test || warm start || cold start || notes&lt;br /&gt;
|-&lt;br /&gt;
| empty profile ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||&lt;br /&gt;
|-&lt;br /&gt;
| everything dirty || || || {{bug|515540}}&lt;br /&gt;
|-&lt;br /&gt;
| min places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || informed by places-stats, {{bug|515540}}&lt;br /&gt;
|-&lt;br /&gt;
| med places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || ditto&lt;br /&gt;
|-&lt;br /&gt;
| max places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || ditto&lt;br /&gt;
|-&lt;br /&gt;
| med session || || || informed by test pilot data&lt;br /&gt;
|-&lt;br /&gt;
| max session || || || ditto&lt;br /&gt;
|-&lt;br /&gt;
| downloads || || ||&lt;br /&gt;
|-&lt;br /&gt;
| url-classifier data || || || data is fully downloaded, should test page-load for a match and no match&lt;br /&gt;
|-&lt;br /&gt;
| form history|| || ||&lt;br /&gt;
|-&lt;br /&gt;
| passwords || || ||&lt;br /&gt;
|-&lt;br /&gt;
| plugins || || ||&lt;br /&gt;
|-&lt;br /&gt;
| content preferences || || ||&lt;br /&gt;
|-&lt;br /&gt;
| extensions || || || top 5?&lt;br /&gt;
|-&lt;br /&gt;
| extension update || || ||&lt;br /&gt;
|-&lt;br /&gt;
| application update || || ||&lt;br /&gt;
|-&lt;br /&gt;
| persona applied || || ||&lt;br /&gt;
|-&lt;br /&gt;
| weave || || ||&lt;br /&gt;
|-&lt;br /&gt;
| jetpack || || ||&lt;br /&gt;
|-&lt;br /&gt;
| ubiquity || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page links are visited || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page has microformats || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page is ssl || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page has plugin || || ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements&amp;diff=186923</id>
		<title>Firefox/Projects/Startup Time Improvements</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements&amp;diff=186923"/>
		<updated>2009-12-01T18:58:41Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Measuring Ts */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&#039;&#039;&#039;Project lead:&#039;&#039;&#039; Dietrich Ayala &amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Project members:&#039;&#039;&#039; Ryan Flint, Drew Willcoxon, David Dahl, Vlad Vukićević, Taras Glek, Joel Reymont, Ben Hsieh&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Investigate areas for improving startup time of the Mozilla platform, find &amp;amp; fix issues that help Fennec and WinCE.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bugs:&#039;&#039;&#039;&lt;br /&gt;
* [http://tinyurl.com/ygbnzmd Open] (identified by &amp;quot;[ts]&amp;quot; in the whiteboard field)&lt;br /&gt;
* [http://tinyurl.com/yjp8d6w Fixed]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Results&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See results in the [http://people.mozilla.org/~dietrich/snapshot/ Performance Snapshot].&lt;br /&gt;
&lt;br /&gt;
= Projects =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Areas of Work:&#039;&#039;&#039;&lt;br /&gt;
* minification&lt;br /&gt;
** {{bug|524858}} - minify js&lt;br /&gt;
** {{bug|513132}} - minify css&lt;br /&gt;
** {{bug|523479}} - minify extension&#039;s contents&lt;br /&gt;
* file combining&lt;br /&gt;
** {{bug|507101}} - combining js components&lt;br /&gt;
** {{bug|509755}} - put modules into a jar&lt;br /&gt;
* {{bug|FILEME}} - [https://bugzilla.mozilla.org/show_bug.cgi?id=279839#c29 string pool for jsxpcom]&lt;br /&gt;
* taking advantage of tracing&lt;br /&gt;
** figure out where we&#039;re not tracing in the startup log&lt;br /&gt;
** traceviz ({{bug|497999}})&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Measurement &amp;amp; Testing&#039;&#039;&#039;&lt;br /&gt;
* cold startup testing&lt;br /&gt;
** &amp;lt;strike&amp;gt;{{bug|510587}} - mac and linux&amp;lt;/strike&amp;gt;&lt;br /&gt;
** {{bug|522807}} - windows&lt;br /&gt;
* dirty profile testing&lt;br /&gt;
** &amp;lt;strike&amp;gt;{{bug|414660}} - infrastructure &amp;amp; places&amp;lt;/strike&amp;gt;&lt;br /&gt;
** {{bug|515540}} - dirty+cold startup&lt;br /&gt;
** {{bug|527596}} - dirty Tp (teehee)&lt;br /&gt;
** {{bug|FILEME}} - test an all-dirty profile&lt;br /&gt;
** {{bug|FILEME}} - other dirty profiles&lt;br /&gt;
* micro-benchmarking&lt;br /&gt;
** {{bug|523146}} - test framework&lt;br /&gt;
** {{bug|479528}} - for location bar&lt;br /&gt;
** {{bug|451607}} - for places UI&lt;br /&gt;
** {{bug|479528}} - for places SQL&lt;br /&gt;
** more, eg: test for opening the 80th tab&lt;br /&gt;
* built-in startup measurement ({{bug|522375}})&lt;br /&gt;
** user-runnable Ts script, paste into js console&lt;br /&gt;
** restarts browser, passing last known time&lt;br /&gt;
** loads data URI that reads startup time and prints it out&lt;br /&gt;
** record startup timestamp as a pref?&lt;br /&gt;
* timeline of the startup path (David, Vlad)&lt;br /&gt;
** Status: incomplete (held up on hangs, nspr changes)&lt;br /&gt;
** [https://wiki.mozilla.org/Firefox/Sprints/Startup_Time_Improvements/StartupPatchUsage#Quick_Start docs]&lt;br /&gt;
** {{bug|480735}} instrumentation&lt;br /&gt;
** {{bug|503605}} visualization ([http://mozilla.ddahl.com/startup/timeline-similie.html Simile timeline], [http://people.mozilla.org/~dietrich/ddahl_sample_output.txt raw log])&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Docs:&#039;&#039;&#039;&lt;br /&gt;
* write best practices recommendation&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inactive Projects&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Mine the Ts DTrace viz/logs (Drew)&lt;br /&gt;
** Status: complete, moved on to filesystem operations below&lt;br /&gt;
** Results&lt;br /&gt;
*** cold startup is heavily I/O-bound. 90% of cold startup time is spent in page faults and other I/O syscalls, especially read, getattrlist, and stat.&lt;br /&gt;
*** majority of time spent after Firefox actually gets up and running is in XBL and CSS.&lt;br /&gt;
* Log and mine filesystem operations during startup (Ryan, Drew)&lt;br /&gt;
** Status: complete, bugs filed for egregious offenders&lt;br /&gt;
** Results&lt;br /&gt;
*** checking out Xperf and others for Windows work&lt;br /&gt;
*** investigating dtrace timing/FS cache issues on OS X&lt;br /&gt;
**** Instruments appears to have the same issues&lt;br /&gt;
*** Simple JS file exec script has yielded [https://bugzilla.mozilla.org/buglist.cgi?bug_id=504513 some results]&lt;br /&gt;
** References&lt;br /&gt;
*** [http://boomswaggerboom.wordpress.com/2009/06/24/firefox-for-mac-os-x-and-filesystem-related-system-calls/ Josh Aas&#039;s post on filesystem calls]&lt;br /&gt;
*** [http://blog.mozilla.com/tglek/2009/07/01/python-gdb-logging-file-io/ Taras&#039; post] on using GDB for logging&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/IO_Scratchpad]]&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/adw_notes|Drew&#039;s notes]]&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/joelr_notes|Joel&#039;s notes]]&lt;br /&gt;
* Find dead code with JSHydra (David Dahl)&lt;br /&gt;
** Status: incomplete, needs tuning and file bugs on dead code found&lt;br /&gt;
** {{bug|506128}} - run jshydra to find js functions that have no callers&lt;br /&gt;
* JSHydra continuous testing&lt;br /&gt;
** possible test scenarios&lt;br /&gt;
*** ending semicolon bug (XXX)&lt;br /&gt;
*** dead code finder&lt;br /&gt;
&lt;br /&gt;
=Status Updates=&lt;br /&gt;
&lt;br /&gt;
* [http://autonome.wordpress.com/2009/10/02/firefox-startup-performance-weekly-summary-4/ 10/2/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/26/firefox-startup-performance-weekly-summary-3/ 9/26/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/18/firefox-startup-performance-weekly-summary-2/ 9/18/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/06/firefox-startup-performance-weekly-summary/ 9/6/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/29/firefox-startup-performance-weekly-roundup/ 8/29/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/22/weekly-firefox-startup-performance-roundup-2/ 8/22/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/18/firefox-performance-the-dont-touch-the-damn-disk-edition/ 8/18/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/08/firefox-startup-performance/ 8/8/09]&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&lt;br /&gt;
;Meta bugs&lt;br /&gt;
* {{bug|459117}} Fennec performance meta bug&lt;br /&gt;
* {{bug|447581}} Startup meta bug&lt;br /&gt;
* {{bug|479078}} Startup research meta bug&lt;br /&gt;
* {{bug|7251}} very old startup meta bug&lt;br /&gt;
&lt;br /&gt;
* Vlad&#039;s blog posts&lt;br /&gt;
** [http://blog.vlad1.com/2009/06/17/firefox-startup-wrangling/ Vlad&#039;s June posting on startup work]&lt;br /&gt;
** Vlad&#039;s July posts:&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/27/startup-part-1/ 1]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/27/startup-again/ 2 - fs cache]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/28/startup-again-2/ 3 - event processing]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/28/measuring-startup/ 4 - measuring startup] &lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/29/startup-again-3/ 5 iosnoop]&lt;br /&gt;
&lt;br /&gt;
* zpao&#039;s JS treemap visualizations&lt;br /&gt;
** [http://playground.zpao.com/dtrace_treemaps2/ newer]&lt;br /&gt;
** [http://playground.zpao.com/dtrace_treemaps/ older]&lt;br /&gt;
&lt;br /&gt;
* Taras&#039; Fennec Startup Work&lt;br /&gt;
** {{bug|459117}} &amp;quot;make fennec faster&amp;quot;, mostly startup bugs&lt;br /&gt;
** [http://people.mozilla.com/~tglek/fennec/startup.txt startup log]&lt;br /&gt;
** {{bug|470116}} various timing scripts&lt;br /&gt;
&lt;br /&gt;
* [[Performance:Home_Page]]&lt;br /&gt;
&lt;br /&gt;
==Tips, Tools==&lt;br /&gt;
&lt;br /&gt;
* Cold startup&lt;br /&gt;
** [http://aegisknight.org/2009/04/flushing-disk-cache/ Flushing Windows&#039; disk cache]&lt;br /&gt;
** [http://tuvix.apple.com/DOCUMENTATION/Darwin/Reference/ManPages/man8/purge.8.html Flushing Mac OS X&#039;s disk cache]&lt;br /&gt;
** [[Firefox/Projects/Startup_Time_Improvements_Notes]]: Vlad&#039;s emails about cold startup, including Linux (maybe move this info to this page)&lt;br /&gt;
&lt;br /&gt;
* Windows Prefetch/Superfetch&lt;br /&gt;
** [http://en.wikipedia.org/wiki/Prefetcher XP Prefetch wiki]&lt;br /&gt;
** [http://en.wikipedia.org/wiki/Windows_Vista_I/O_technologies#SuperFetch Vista/Win7 SuperFetch wiki]&lt;br /&gt;
** [http://members.rushmore.com/~jsky/id37.html useful Pre/SuperFetch overview]&lt;br /&gt;
** [http://jessekornblum.com/presentations/dodcc08-2.html Presentation slides on the guts of Pref/SuperFetch by military forensic analyst]&lt;br /&gt;
*** Prefetch&lt;br /&gt;
**** Profile for each application: List of DLLs used, Run count, Time stamps&lt;br /&gt;
**** Prefetch files stored in %SystemRoot%\Prefetch: .pf extension, Up to 128 are kept&lt;br /&gt;
**** Can tell if same app run from multiple locations&lt;br /&gt;
*** SuperFetch&lt;br /&gt;
**** turn off: net stop sysmain&lt;br /&gt;
**** AG*.db files, contain &amp;quot;scenarios&amp;quot; for preloading&lt;br /&gt;
** [http://technet.microsoft.com/en-us/magazine/2007.03.vistakernel.aspx Technet article on Vista mem mgmnt]&lt;br /&gt;
** [http://www.howtogeek.com/howto/windows-vista/change-superfetch-to-only-cache-system-boot-files-in-vista/ registry keys for toggling SuperFetch]&lt;br /&gt;
&lt;br /&gt;
* DTrace&lt;br /&gt;
** [https://wiki.mozilla.org/Performance/Optimizing_JavaScript_with_DTrace nuts and bolts how-to for getting dtrace running with mozilla]&lt;br /&gt;
** [http://www.opensolaris.org/os/project/mozilla-dtrace/ project overview of integrating dtrace with mozilla]&lt;br /&gt;
** [http://www.opensolaris.org/os/community/dtrace/ dtrace community page, lots of links]&lt;br /&gt;
** [http://www.sun.com/bigadmin/content/dtrace/ dtrace homepage? not as useful as previous link]&lt;br /&gt;
** [http://wikis.sun.com/display/DTrace/Introduction intro from dtrace guidebook, really useful but not mozilla/js-specific]&lt;br /&gt;
** [http://blogs.sun.com/jmr/entry/dtrace_mozilla_rfe_javascript_tracing brief descriptions of the javascript* probes]&lt;br /&gt;
** [http://blog.mozilla.com/dmandelin/2008/02/14/dtrace-c-mysteries-solved/ David Mandelin&#039;s notes on tracing C++ code]&lt;br /&gt;
&lt;br /&gt;
* comparing dynamic linking time between firefox and safari on mac&lt;br /&gt;
** DYLD_PRINT_STATISTICS=YES /Applications/Firefox.app/Contents/MacOS/firefox-bin&lt;br /&gt;
** DYLD_PRINT_STATISTICS=YES open -a Safari&lt;br /&gt;
&lt;br /&gt;
==Fastload==&lt;br /&gt;
* why does js_Execute take so long for fastloaded components?&lt;br /&gt;
* [http://groups.google.com/group/mozilla.dev.platform/browse_thread/thread/42c0e9df84b935fe what is fastload?]&lt;br /&gt;
* [http://kb.mozillazine.org/Nglayout.debug.disable_xul_fastload fastload pref docs]&lt;br /&gt;
&lt;br /&gt;
==Measuring Ts==&lt;br /&gt;
&lt;br /&gt;
We&#039;ve been using a method Vlad blogged about [http://blog.vlad1.com/2009/07/28/measuring-startup/ here]. The steps are below.&lt;br /&gt;
&lt;br /&gt;
# save [http://people.mozilla.com/~vladimir/misc/startup.html this html file] somewhere locally&lt;br /&gt;
# create a new profile, run Firefox with it at least once, so all files are created, etc&lt;br /&gt;
# execute this command, with your profile name substituted, and invoking firefox in a way appropriate for your platform:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
./firefox -P YourProfileName -no-remote file:///..../startup.html#`python -c &#039;import time; print int(time.time() * 1000);&#039;`&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is specific to Mac OSX and is required to evict Firefox code pages from memory and clear the Unified Buffer Cache (UBC). &amp;lt;code&amp;gt;purge&amp;lt;/code&amp;gt; does NOT do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
FF=/tmp/firefox&lt;br /&gt;
&lt;br /&gt;
mkdir $FF &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
umount $FF &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
mount_hfs /dev/disk1s2 $FF&lt;br /&gt;
&lt;br /&gt;
$FF/Minefield$*.app/Contents/MacOS/firefox-bin -no-remote -foreground file://$FF/startup.html#`python -c &#039;import time; print int(time.time() * 1000);&#039;`&lt;br /&gt;
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This assumes that your removable media is at /dev/disk1s2. &lt;br /&gt;
&lt;br /&gt;
First, mount you external USB HD normally and use &amp;lt;code&amp;gt;df&amp;lt;/code&amp;gt; to see what device is being used. Then eject the drive using &amp;lt;code&amp;gt;diskutil umount /Volumes/YourDrive&amp;lt;/code&amp;gt; and you are set. &lt;br /&gt;
&lt;br /&gt;
Do not eject the device using the Finder as that will not make it available at /dev/disk1s2 or wherever it was.&lt;br /&gt;
&lt;br /&gt;
==Test Coverage==&lt;br /&gt;
&lt;br /&gt;
This is an index of Firefox startup scenarios which need automated test coverage.&lt;br /&gt;
&lt;br /&gt;
TODO:&lt;br /&gt;
* groups: chrome, content, extensions, labs, other?&lt;br /&gt;
* mark which need no-chrome testing&lt;br /&gt;
&lt;br /&gt;
{| border=solid black 1px&lt;br /&gt;
| test || warm start || cold start || notes&lt;br /&gt;
|-&lt;br /&gt;
| empty profile ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||&lt;br /&gt;
|-&lt;br /&gt;
| everything dirty || || || {{bug|515540}}&lt;br /&gt;
|-&lt;br /&gt;
| min places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || informed by places-stats, {{bug|515540}}&lt;br /&gt;
|-&lt;br /&gt;
| med places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || ditto&lt;br /&gt;
|-&lt;br /&gt;
| max places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || ditto&lt;br /&gt;
|-&lt;br /&gt;
| med session || || || informed by test pilot data&lt;br /&gt;
|-&lt;br /&gt;
| max session || || || ditto&lt;br /&gt;
|-&lt;br /&gt;
| downloads || || ||&lt;br /&gt;
|-&lt;br /&gt;
| url-classifier data || || || data is fully downloaded, should test page-load for a match and no match&lt;br /&gt;
|-&lt;br /&gt;
| form history|| || ||&lt;br /&gt;
|-&lt;br /&gt;
| passwords || || ||&lt;br /&gt;
|-&lt;br /&gt;
| plugins || || ||&lt;br /&gt;
|-&lt;br /&gt;
| content preferences || || ||&lt;br /&gt;
|-&lt;br /&gt;
| extensions || || || top 5?&lt;br /&gt;
|-&lt;br /&gt;
| extension update || || ||&lt;br /&gt;
|-&lt;br /&gt;
| application update || || ||&lt;br /&gt;
|-&lt;br /&gt;
| persona applied || || ||&lt;br /&gt;
|-&lt;br /&gt;
| weave || || ||&lt;br /&gt;
|-&lt;br /&gt;
| jetpack || || ||&lt;br /&gt;
|-&lt;br /&gt;
| ubiquity || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page links are visited || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page has microformats || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page is ssl || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page has plugin || || ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements&amp;diff=186920</id>
		<title>Firefox/Projects/Startup Time Improvements</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements&amp;diff=186920"/>
		<updated>2009-12-01T18:56:57Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Measuring Ts */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&#039;&#039;&#039;Project lead:&#039;&#039;&#039; Dietrich Ayala &amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Project members:&#039;&#039;&#039; Ryan Flint, Drew Willcoxon, David Dahl, Vlad Vukićević, Taras Glek, Joel Reymont, Ben Hsieh&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Investigate areas for improving startup time of the Mozilla platform, find &amp;amp; fix issues that help Fennec and WinCE.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bugs:&#039;&#039;&#039;&lt;br /&gt;
* [http://tinyurl.com/ygbnzmd Open] (identified by &amp;quot;[ts]&amp;quot; in the whiteboard field)&lt;br /&gt;
* [http://tinyurl.com/yjp8d6w Fixed]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Results&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See results in the [http://people.mozilla.org/~dietrich/snapshot/ Performance Snapshot].&lt;br /&gt;
&lt;br /&gt;
= Projects =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Areas of Work:&#039;&#039;&#039;&lt;br /&gt;
* minification&lt;br /&gt;
** {{bug|524858}} - minify js&lt;br /&gt;
** {{bug|513132}} - minify css&lt;br /&gt;
** {{bug|523479}} - minify extension&#039;s contents&lt;br /&gt;
* file combining&lt;br /&gt;
** {{bug|507101}} - combining js components&lt;br /&gt;
** {{bug|509755}} - put modules into a jar&lt;br /&gt;
* {{bug|FILEME}} - [https://bugzilla.mozilla.org/show_bug.cgi?id=279839#c29 string pool for jsxpcom]&lt;br /&gt;
* taking advantage of tracing&lt;br /&gt;
** figure out where we&#039;re not tracing in the startup log&lt;br /&gt;
** traceviz ({{bug|497999}})&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Measurement &amp;amp; Testing&#039;&#039;&#039;&lt;br /&gt;
* cold startup testing&lt;br /&gt;
** &amp;lt;strike&amp;gt;{{bug|510587}} - mac and linux&amp;lt;/strike&amp;gt;&lt;br /&gt;
** {{bug|522807}} - windows&lt;br /&gt;
* dirty profile testing&lt;br /&gt;
** &amp;lt;strike&amp;gt;{{bug|414660}} - infrastructure &amp;amp; places&amp;lt;/strike&amp;gt;&lt;br /&gt;
** {{bug|515540}} - dirty+cold startup&lt;br /&gt;
** {{bug|527596}} - dirty Tp (teehee)&lt;br /&gt;
** {{bug|FILEME}} - test an all-dirty profile&lt;br /&gt;
** {{bug|FILEME}} - other dirty profiles&lt;br /&gt;
* micro-benchmarking&lt;br /&gt;
** {{bug|523146}} - test framework&lt;br /&gt;
** {{bug|479528}} - for location bar&lt;br /&gt;
** {{bug|451607}} - for places UI&lt;br /&gt;
** {{bug|479528}} - for places SQL&lt;br /&gt;
** more, eg: test for opening the 80th tab&lt;br /&gt;
* built-in startup measurement ({{bug|522375}})&lt;br /&gt;
** user-runnable Ts script, paste into js console&lt;br /&gt;
** restarts browser, passing last known time&lt;br /&gt;
** loads data URI that reads startup time and prints it out&lt;br /&gt;
** record startup timestamp as a pref?&lt;br /&gt;
* timeline of the startup path (David, Vlad)&lt;br /&gt;
** Status: incomplete (held up on hangs, nspr changes)&lt;br /&gt;
** [https://wiki.mozilla.org/Firefox/Sprints/Startup_Time_Improvements/StartupPatchUsage#Quick_Start docs]&lt;br /&gt;
** {{bug|480735}} instrumentation&lt;br /&gt;
** {{bug|503605}} visualization ([http://mozilla.ddahl.com/startup/timeline-similie.html Simile timeline], [http://people.mozilla.org/~dietrich/ddahl_sample_output.txt raw log])&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Docs:&#039;&#039;&#039;&lt;br /&gt;
* write best practices recommendation&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inactive Projects&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Mine the Ts DTrace viz/logs (Drew)&lt;br /&gt;
** Status: complete, moved on to filesystem operations below&lt;br /&gt;
** Results&lt;br /&gt;
*** cold startup is heavily I/O-bound. 90% of cold startup time is spent in page faults and other I/O syscalls, especially read, getattrlist, and stat.&lt;br /&gt;
*** majority of time spent after Firefox actually gets up and running is in XBL and CSS.&lt;br /&gt;
* Log and mine filesystem operations during startup (Ryan, Drew)&lt;br /&gt;
** Status: complete, bugs filed for egregious offenders&lt;br /&gt;
** Results&lt;br /&gt;
*** checking out Xperf and others for Windows work&lt;br /&gt;
*** investigating dtrace timing/FS cache issues on OS X&lt;br /&gt;
**** Instruments appears to have the same issues&lt;br /&gt;
*** Simple JS file exec script has yielded [https://bugzilla.mozilla.org/buglist.cgi?bug_id=504513 some results]&lt;br /&gt;
** References&lt;br /&gt;
*** [http://boomswaggerboom.wordpress.com/2009/06/24/firefox-for-mac-os-x-and-filesystem-related-system-calls/ Josh Aas&#039;s post on filesystem calls]&lt;br /&gt;
*** [http://blog.mozilla.com/tglek/2009/07/01/python-gdb-logging-file-io/ Taras&#039; post] on using GDB for logging&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/IO_Scratchpad]]&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/adw_notes|Drew&#039;s notes]]&lt;br /&gt;
*** [[Firefox/Projects/Startup_Time_Improvements/joelr_notes|Joel&#039;s notes]]&lt;br /&gt;
* Find dead code with JSHydra (David Dahl)&lt;br /&gt;
** Status: incomplete, needs tuning and file bugs on dead code found&lt;br /&gt;
** {{bug|506128}} - run jshydra to find js functions that have no callers&lt;br /&gt;
* JSHydra continuous testing&lt;br /&gt;
** possible test scenarios&lt;br /&gt;
*** ending semicolon bug (XXX)&lt;br /&gt;
*** dead code finder&lt;br /&gt;
&lt;br /&gt;
=Status Updates=&lt;br /&gt;
&lt;br /&gt;
* [http://autonome.wordpress.com/2009/10/02/firefox-startup-performance-weekly-summary-4/ 10/2/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/26/firefox-startup-performance-weekly-summary-3/ 9/26/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/18/firefox-startup-performance-weekly-summary-2/ 9/18/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/09/06/firefox-startup-performance-weekly-summary/ 9/6/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/29/firefox-startup-performance-weekly-roundup/ 8/29/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/22/weekly-firefox-startup-performance-roundup-2/ 8/22/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/18/firefox-performance-the-dont-touch-the-damn-disk-edition/ 8/18/09]&lt;br /&gt;
* [http://autonome.wordpress.com/2009/08/08/firefox-startup-performance/ 8/8/09]&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&lt;br /&gt;
;Meta bugs&lt;br /&gt;
* {{bug|459117}} Fennec performance meta bug&lt;br /&gt;
* {{bug|447581}} Startup meta bug&lt;br /&gt;
* {{bug|479078}} Startup research meta bug&lt;br /&gt;
* {{bug|7251}} very old startup meta bug&lt;br /&gt;
&lt;br /&gt;
* Vlad&#039;s blog posts&lt;br /&gt;
** [http://blog.vlad1.com/2009/06/17/firefox-startup-wrangling/ Vlad&#039;s June posting on startup work]&lt;br /&gt;
** Vlad&#039;s July posts:&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/27/startup-part-1/ 1]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/27/startup-again/ 2 - fs cache]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/28/startup-again-2/ 3 - event processing]&lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/28/measuring-startup/ 4 - measuring startup] &lt;br /&gt;
*** [http://blog.vlad1.com/2009/07/29/startup-again-3/ 5 iosnoop]&lt;br /&gt;
&lt;br /&gt;
* zpao&#039;s JS treemap visualizations&lt;br /&gt;
** [http://playground.zpao.com/dtrace_treemaps2/ newer]&lt;br /&gt;
** [http://playground.zpao.com/dtrace_treemaps/ older]&lt;br /&gt;
&lt;br /&gt;
* Taras&#039; Fennec Startup Work&lt;br /&gt;
** {{bug|459117}} &amp;quot;make fennec faster&amp;quot;, mostly startup bugs&lt;br /&gt;
** [http://people.mozilla.com/~tglek/fennec/startup.txt startup log]&lt;br /&gt;
** {{bug|470116}} various timing scripts&lt;br /&gt;
&lt;br /&gt;
* [[Performance:Home_Page]]&lt;br /&gt;
&lt;br /&gt;
==Tips, Tools==&lt;br /&gt;
&lt;br /&gt;
* Cold startup&lt;br /&gt;
** [http://aegisknight.org/2009/04/flushing-disk-cache/ Flushing Windows&#039; disk cache]&lt;br /&gt;
** [http://tuvix.apple.com/DOCUMENTATION/Darwin/Reference/ManPages/man8/purge.8.html Flushing Mac OS X&#039;s disk cache]&lt;br /&gt;
** [[Firefox/Projects/Startup_Time_Improvements_Notes]]: Vlad&#039;s emails about cold startup, including Linux (maybe move this info to this page)&lt;br /&gt;
&lt;br /&gt;
* Windows Prefetch/Superfetch&lt;br /&gt;
** [http://en.wikipedia.org/wiki/Prefetcher XP Prefetch wiki]&lt;br /&gt;
** [http://en.wikipedia.org/wiki/Windows_Vista_I/O_technologies#SuperFetch Vista/Win7 SuperFetch wiki]&lt;br /&gt;
** [http://members.rushmore.com/~jsky/id37.html useful Pre/SuperFetch overview]&lt;br /&gt;
** [http://jessekornblum.com/presentations/dodcc08-2.html Presentation slides on the guts of Pref/SuperFetch by military forensic analyst]&lt;br /&gt;
*** Prefetch&lt;br /&gt;
**** Profile for each application: List of DLLs used, Run count, Time stamps&lt;br /&gt;
**** Prefetch files stored in %SystemRoot%\Prefetch: .pf extension, Up to 128 are kept&lt;br /&gt;
**** Can tell if same app run from multiple locations&lt;br /&gt;
*** SuperFetch&lt;br /&gt;
**** turn off: net stop sysmain&lt;br /&gt;
**** AG*.db files, contain &amp;quot;scenarios&amp;quot; for preloading&lt;br /&gt;
** [http://technet.microsoft.com/en-us/magazine/2007.03.vistakernel.aspx Technet article on Vista mem mgmnt]&lt;br /&gt;
** [http://www.howtogeek.com/howto/windows-vista/change-superfetch-to-only-cache-system-boot-files-in-vista/ registry keys for toggling SuperFetch]&lt;br /&gt;
&lt;br /&gt;
* DTrace&lt;br /&gt;
** [https://wiki.mozilla.org/Performance/Optimizing_JavaScript_with_DTrace nuts and bolts how-to for getting dtrace running with mozilla]&lt;br /&gt;
** [http://www.opensolaris.org/os/project/mozilla-dtrace/ project overview of integrating dtrace with mozilla]&lt;br /&gt;
** [http://www.opensolaris.org/os/community/dtrace/ dtrace community page, lots of links]&lt;br /&gt;
** [http://www.sun.com/bigadmin/content/dtrace/ dtrace homepage? not as useful as previous link]&lt;br /&gt;
** [http://wikis.sun.com/display/DTrace/Introduction intro from dtrace guidebook, really useful but not mozilla/js-specific]&lt;br /&gt;
** [http://blogs.sun.com/jmr/entry/dtrace_mozilla_rfe_javascript_tracing brief descriptions of the javascript* probes]&lt;br /&gt;
** [http://blog.mozilla.com/dmandelin/2008/02/14/dtrace-c-mysteries-solved/ David Mandelin&#039;s notes on tracing C++ code]&lt;br /&gt;
&lt;br /&gt;
* comparing dynamic linking time between firefox and safari on mac&lt;br /&gt;
** DYLD_PRINT_STATISTICS=YES /Applications/Firefox.app/Contents/MacOS/firefox-bin&lt;br /&gt;
** DYLD_PRINT_STATISTICS=YES open -a Safari&lt;br /&gt;
&lt;br /&gt;
==Fastload==&lt;br /&gt;
* why does js_Execute take so long for fastloaded components?&lt;br /&gt;
* [http://groups.google.com/group/mozilla.dev.platform/browse_thread/thread/42c0e9df84b935fe what is fastload?]&lt;br /&gt;
* [http://kb.mozillazine.org/Nglayout.debug.disable_xul_fastload fastload pref docs]&lt;br /&gt;
&lt;br /&gt;
==Measuring Ts==&lt;br /&gt;
&lt;br /&gt;
We&#039;ve been using a method Vlad blogged about [http://blog.vlad1.com/2009/07/28/measuring-startup/ here]. The steps are below.&lt;br /&gt;
&lt;br /&gt;
# save [http://people.mozilla.com/~vladimir/misc/startup.html this html file] somewhere locally&lt;br /&gt;
# create a new profile, run Firefox with it at least once, so all files are created, etc&lt;br /&gt;
# execute this command, with your profile name substituted, and invoking firefox in a way appropriate for your platform:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
./firefox -P YourProfileName -no-remote file:///..../startup.html#`python -c &#039;import time; print int(time.time() * 1000);&#039;`&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is specific to Mac OSX and is required to evict Firefox code pages from memory and clear the Unified Buffer Cache (UBC). &amp;lt;code&amp;gt;purge&amp;lt;/code&amp;gt; does NOT do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
FF=/tmp/firefox&lt;br /&gt;
&lt;br /&gt;
mkdir $FF &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
umount $FF &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
mount_hfs /dev/disk1s2 $FF&lt;br /&gt;
&lt;br /&gt;
$FF/Minefield$*.app/Contents/MacOS/firefox-bin -no-remote -foreground file://$FF/startup.html#`python -c &#039;import time; print int(time.time() * 1000);&#039;`&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This assumes that your removable media is at /dev/disk1s2. &lt;br /&gt;
&lt;br /&gt;
First, mount you external USB HD normally and use &amp;lt;code&amp;gt;df&amp;lt;/code&amp;gt; to see what device is being used. Then eject the drive using &amp;lt;code&amp;gt;diskutil umount /Volumes/YourDrive&amp;lt;/code&amp;gt; and you are set. &lt;br /&gt;
&lt;br /&gt;
Do not eject the device using the Finder as that will not make it available at /dev/disk1s2 or wherever it was.&lt;br /&gt;
&lt;br /&gt;
==Test Coverage==&lt;br /&gt;
&lt;br /&gt;
This is an index of Firefox startup scenarios which need automated test coverage.&lt;br /&gt;
&lt;br /&gt;
TODO:&lt;br /&gt;
* groups: chrome, content, extensions, labs, other?&lt;br /&gt;
* mark which need no-chrome testing&lt;br /&gt;
&lt;br /&gt;
{| border=solid black 1px&lt;br /&gt;
| test || warm start || cold start || notes&lt;br /&gt;
|-&lt;br /&gt;
| empty profile ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||&lt;br /&gt;
|-&lt;br /&gt;
| everything dirty || || || {{bug|515540}}&lt;br /&gt;
|-&lt;br /&gt;
| min places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || informed by places-stats, {{bug|515540}}&lt;br /&gt;
|-&lt;br /&gt;
| med places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || ditto&lt;br /&gt;
|-&lt;br /&gt;
| max places ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes ||style=&amp;quot;background-color: lawngreen&amp;quot;|yes || ditto&lt;br /&gt;
|-&lt;br /&gt;
| med session || || || informed by test pilot data&lt;br /&gt;
|-&lt;br /&gt;
| max session || || || ditto&lt;br /&gt;
|-&lt;br /&gt;
| downloads || || ||&lt;br /&gt;
|-&lt;br /&gt;
| url-classifier data || || || data is fully downloaded, should test page-load for a match and no match&lt;br /&gt;
|-&lt;br /&gt;
| form history|| || ||&lt;br /&gt;
|-&lt;br /&gt;
| passwords || || ||&lt;br /&gt;
|-&lt;br /&gt;
| plugins || || ||&lt;br /&gt;
|-&lt;br /&gt;
| content preferences || || ||&lt;br /&gt;
|-&lt;br /&gt;
| extensions || || || top 5?&lt;br /&gt;
|-&lt;br /&gt;
| extension update || || ||&lt;br /&gt;
|-&lt;br /&gt;
| application update || || ||&lt;br /&gt;
|-&lt;br /&gt;
| persona applied || || ||&lt;br /&gt;
|-&lt;br /&gt;
| weave || || ||&lt;br /&gt;
|-&lt;br /&gt;
| jetpack || || ||&lt;br /&gt;
|-&lt;br /&gt;
| ubiquity || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page links are visited || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page has microformats || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page is ssl || || ||&lt;br /&gt;
|-&lt;br /&gt;
| page has plugin || || ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=177106</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=177106"/>
		<updated>2009-10-20T19:03:33Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Can Android run a completely native app? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 12, 2009 ==&lt;br /&gt;
&lt;br /&gt;
Via Chris Lord...&lt;br /&gt;
&lt;br /&gt;
The [http://hg.mozilla.org/incubator/offscreen headless branch of Mozilla that we work on] renders to system memory and it is up to the embedder to get this to a texture however they like. We have our own embedding library that uses this with Clutter&lt;br /&gt;
[http://git.clutter-project.org/?r=clutter-mozembed clutter-mozembed] and we just upload each changed region to the texture.&lt;br /&gt;
&lt;br /&gt;
A possible speed-up is to use a shared memory pixmap and texture-from-pixmap (or whatever the platform&#039;s equivalent is), which&lt;br /&gt;
would remove the need to copy from system to video memory.&lt;br /&gt;
&lt;br /&gt;
I wrote a (now out-dated, but still relevant) [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten guide on building the Moblin browser components] on my blog. There&#039;s also a [http://chrislord.net/files/moz-headless-screenshot.c short demo application I wrote] that just uses mozilla-headless alone to take a screenshot of a web-page. &lt;br /&gt;
&lt;br /&gt;
Unfortunately, there is no documentation beyond the standard Mozilla documentation and the source-code (and the above-mentioned links).&lt;br /&gt;
&lt;br /&gt;
I think the easiest way to port Firefox to android would be to write an android-backend (which could well be based on our headless backend) - I didn&#039;t think that the Android native development kit was fully featured enough to allow something like this though?&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
You can&#039;t run Firefox with the headless backend as it is, it&#039;s designed to be embedded and for libxul to be used. The headless backend is also heavily dependent on GLib (for the main loop, signals and idle handlers).&lt;br /&gt;
&lt;br /&gt;
If you wanted to run Firefox, you&#039;d have to write a new backend, or modify an existing one, to provide the application framework. In the gtk2 and headless backends, this is GLib-based. The Gtk2 backend creates a GtkWindow and that is how the user sees and interacts with the application. On the headless backend, there is no visible window. It can only be used for embedding via libxul.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
Chris has a [http://chrislord.net/files/fosdem-09-slides.odp presentation] that explains the headless branch a bit and [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten instructions on how to build it].&lt;br /&gt;
&lt;br /&gt;
--- &lt;br /&gt;
&lt;br /&gt;
There&#039;s an [https://bugzilla.mozilla.org/show_bug.cgi?id=446591 existing bug] that deals with headless UI.&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Can Android run a completely native app? ==&lt;br /&gt;
&lt;br /&gt;
According to  [http://sites.google.com/site/io/anatomy--physiology-of-an-android Anatomy and physiology] and [http://developer.android.com/guide/topics/fundamentals.html Android Fundamentals], each Android process has its own Java virtual machine (VM), so application code runs in isolation from the code of all other applications. &lt;br /&gt;
&lt;br /&gt;
Android processes (Java VMs) communicate with the Home App and various system services via the [http://en.wikipedia.org/wiki/OpenBinder Binder IPC] described using [http://developer.android.com/guide/developing/tools/aidl.html Android Interface Definition Language (AIDL)].&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;Home Application&#039;&#039; (Launcher) is the app that displays the Android desktop and allows the [http:///Volumes/android/mydroid/frameworks/base/core/java/android/app/LauncherActivity.java launching of other apps] by clicking on their icons. &lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;activity&#039;&#039; presents a visual user interface for one focused endeavor the user can undertake. For example, an activity might present a list of menu items users can choose from or it might display photographs along with their captions. A text messaging application might have one activity that shows a list of contacts to send messages to, a second activity to write the message to the chosen contact, and other activities to review old messages or change settings.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;task&#039;&#039; is a group of related activities. May include activities from other apps, running in other processes, e.g. map viewer. A task has an activity stack. &lt;br /&gt;
&lt;br /&gt;
Any given activity  &lt;br /&gt;
&lt;br /&gt;
* Has a content view that is created using a layout resource.&lt;br /&gt;
* Can be floating or embedded inside another activity.&lt;br /&gt;
* Has a pause callback invoked when the user is leaving the activity.&lt;br /&gt;
* Is visible when it&#039;s at the top of the stack for the current task.&lt;br /&gt;
* Is paused when there&#039;s another activity on top of it but remains visible. It has lost focus but remains completely alive and attached to the window manager but can be killed in low memory conditions.&lt;br /&gt;
* Is stopped when it&#039;s completely obscured by another activity. The window is hidden and activity will be killed when memory is needed elsewhere. &lt;br /&gt;
* Has a finish callback that may be called when the activity is being evicted from memory.&lt;br /&gt;
* Generates a thumbnail of the activity via a callback that&#039;s called before pausing.&lt;br /&gt;
* Receives trackball and key events via callbacks.&lt;br /&gt;
&lt;br /&gt;
When an app icon is clicked, the Home app uses the package manager to retrive app info and package it into an [http:///Volumes/android/mydroid/frameworks/base/core/java/android/content/Intent.java intent], an asynchronous message with information necessary to start a given activity. The Home app then uses startActivity, a method of Context to launch the activity. [http:///Volumes/android/mydroid/frameworks/base/core/java/android/content/Context.java Context is an abstract class] whose implementation is provided by the Android system.&lt;br /&gt;
&lt;br /&gt;
The launch request is sent via the Binder IPC to the [http:///Volumes/android/mydroid/frameworks/base/services/java/com/android/server/am/ActivityManagerService.java Activity Manager Service] which uses the [http:///Volumes/android/mydroid/frameworks/base/core/java/android/os/Process.java Process] class to start an [http:///Volumes/android/mydroid/frameworks/base/core/java/android/app/ActivityThread.java Activity Thread] in a new instance of the Dalvik Java VM via the [http:///Volumes/android/mydroid//Volumes/android/mydroid/system/core/libcutils/zygote.c Zygote].&lt;br /&gt;
&lt;br /&gt;
The mechanism above assumes Java is used to implement activities. For example, the first non-option argument to Zygote should be a class name in the system class path. Also, [http://developer.android.com/guide/developing/tools/aidl.html aidl command-line tool] only generates Java code for Binder IPCs. &lt;br /&gt;
&lt;br /&gt;
While I&#039;m confident that I could write a native application that plugs into the Android event stream as well as the activity, window, etc. managers, doing so would require adding C++ code generation to the &#039;&#039;aidl tool&#039;&#039; and implementing the portion of the Android Java SDK that deals with the activity life cycle. &lt;br /&gt;
&lt;br /&gt;
Still, it will not be possible to launch a native app from the Home app due to the Java assumptions in the core launching mechanism, so a Java shim will be required. There may be a great deal of flexibility in running a completely native app since, for example, OpenGL ES is not required and the screen (surface) buffer can be written to directly. &lt;br /&gt;
&lt;br /&gt;
Another alternative is to let the Java shim handle act as an invisible &#039;&#039;activity&#039;&#039; that uses the NDK to pass events to native code running in a shared library. OpenGL ES will be required in the latter case to write to a pre-configured screen context.&lt;br /&gt;
&lt;br /&gt;
To summarize...&lt;br /&gt;
&lt;br /&gt;
The Android activity and application launching mechanism assumes Java. Apps run in separate processes (and Java VMs) and talk to system services via the Binder IPC.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no C++ code generation from the AIDL that describes the IPC so we&#039;ll need to write that. We&#039;ll also need to write a whole bunch of other C++ code that covers the portion of the Android Java SDK that deals with the application life cycle to be able to suspend, resume, stop and generally be a good citizen of the Android desktop (Home application).&lt;br /&gt;
&lt;br /&gt;
We won&#039;t be able to launch a native app right from the Android desktop so a Java shim will be needed. If we go the long route and talk to system services using Binder IPC, then we won&#039;t need OpenGL ES and will be able to write directly to the screen buffer (surface). If we make our Java shim a proper Android activity that feeds all kinds of events to our shared library using the NDK (JNI), then we&#039;ll be required to use OpenGL ES to write to a pre-configured context as well as potentially implement calls back to Java from our native libraries.&lt;br /&gt;
&lt;br /&gt;
I volunteer to write the C++ from AIDL code generator, as well as re-implement necessary portions of the Android Java SDK in C++. Many a C++ programmer will thank us for that and announcing a Mozilla Android C++ SDK may actually force Google&#039;s hand and make them release something official.&lt;br /&gt;
&lt;br /&gt;
Going the officially sanctioned way and using a proper Java activity shim with the NDK will positively be easier initially but may turn out to be a pain down the road what with OpenGL ES and all the data flying back and forth between Java and native code.&lt;br /&gt;
&lt;br /&gt;
== Sample external application Makefile ==&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you can build your own native apps without being shoehorned into the Android SDK build structure. I got this by massaging the output of &#039;&#039;make showcommands&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SDK := /Volumes/android/mydroid&lt;br /&gt;
TOOLCHAIN := $(SDK)/prebuilt/darwin-x86/toolchain/arm-eabi-4.2.1&lt;br /&gt;
ABILIB := $(TOOLCHAIN)/lib/gcc/arm-eabi/4.2.1/&lt;br /&gt;
BIN := $(TOOLCHAIN)/bin&lt;br /&gt;
C++ := $(BIN)/arm-eabi-g++&lt;br /&gt;
CC := $(BIN)/arm-eabi-gcc&lt;br /&gt;
&lt;br /&gt;
INCLUDE := \&lt;br /&gt;
  -I$(SDK)/system/core/include \&lt;br /&gt;
  -I$(SDK)/hardware/libhardware/include \&lt;br /&gt;
  -I$(SDK)/hardware/libhardware_legacy/include \&lt;br /&gt;
  -I$(SDK)/hardware/ril/include \&lt;br /&gt;
  -I$(SDK)/dalvik/libnativehelper/include \&lt;br /&gt;
  -I$(SDK)/frameworks/base/include \&lt;br /&gt;
  -I$(SDK)/frameworks/base/opengl/include \&lt;br /&gt;
  -I$(SDK)/external/skia/include \&lt;br /&gt;
  -I$(SDK)/out/target/product/generic/obj/include \&lt;br /&gt;
  -I$(SDK)/bionic/libc/arch-arm/include \&lt;br /&gt;
  -I$(SDK)/bionic/libc/include \&lt;br /&gt;
  -I$(SDK)/bionic/libstdc++/include \&lt;br /&gt;
  -I$(SDK)/bionic/libc/kernel/common \&lt;br /&gt;
  -I$(SDK)/bionic/libc/kernel/arch-arm \&lt;br /&gt;
  -I$(SDK)/bionic/libm/include \&lt;br /&gt;
  -I$(SDK)/bionic/libm/include/arch/arm \&lt;br /&gt;
  -I$(SDK)/bionic/libthread_db/include \&lt;br /&gt;
  -I$(SDK)/frameworks/base/cmds/demo \&lt;br /&gt;
  -I$(SDK)/system/core/include/arch/linux-arm \&lt;br /&gt;
  -include $(SDK)/system/core/include/arch/linux-arm/AndroidConfig.h \&lt;br /&gt;
  $(NULL)&lt;br /&gt;
  &lt;br /&gt;
CFLAGS = \&lt;br /&gt;
  -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5TE__ -DANDROID \&lt;br /&gt;
  -DSK_RELEASE -DNDEBUG -UDEBUG \&lt;br /&gt;
  -mthumb -mthumb-interwork -msoft-float -march=armv5te -mtune=xscale \&lt;br /&gt;
  -fpic -fno-exceptions -ffunction-sections -funwind-tables -fstack-protector \&lt;br /&gt;
  -fno-short-enums -fmessage-length=0 -finline-functions -fno-inline-functions-called-once \&lt;br /&gt;
  -fgcse-after-reload -frerun-cse-after-loop -frename-registers -fvisibility-inlines-hidden \&lt;br /&gt;
  -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -fno-rtti \&lt;br /&gt;
  -W -Wall -Wno-multichar -Wno-unused -Werror=return-type -Wstrict-aliasing=2 \&lt;br /&gt;
  -Wnon-virtual-dtor -Werror=return-type \&lt;br /&gt;
  -MD -Os -g \&lt;br /&gt;
  $(NULL)&lt;br /&gt;
 &lt;br /&gt;
LIBDIR := $(SDK)/out/target/product/generic/obj/lib&lt;br /&gt;
&lt;br /&gt;
LIBS := -lui -llog -lutils -lc -lstdc++ -lm $(LIBDIR)/crtbegin_dynamic.o &lt;br /&gt;
  &lt;br /&gt;
LDFLAGS := \&lt;br /&gt;
  -nostdlib -Bdynamic -Wl,--no-undefined -Wl,-T,$(SDK)/build/core/armelf.x \&lt;br /&gt;
  -Wl,-dynamic-linker,$(SDK)/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc \&lt;br /&gt;
  -L$(LIBDIR) -Wl,-rpath-link=$(LIBDIR) \&lt;br /&gt;
  $(NULL)&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
all: demo&lt;br /&gt;
&lt;br /&gt;
demo: surfaceflinger.o demo.o&lt;br /&gt;
	$(C++) $(LDFLAGS) -o demo $(LIBS) surfaceflinger.o demo.o \&lt;br /&gt;
		$(ABILIB)/interwork/libgcc.a $(LIBDIR)/crtend_android.o&lt;br /&gt;
&lt;br /&gt;
surfaceflinger.o: &lt;br /&gt;
	$(C++) $(INCLUDE) -c $(CFLAGS) surfaceflinger.cpp&lt;br /&gt;
&lt;br /&gt;
demo.o:&lt;br /&gt;
	$(CC) $(INCLUDE) -c $(CFLAGS) demo.c&lt;br /&gt;
&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f demo *.o	&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction to the Android Window System ==&lt;br /&gt;
&lt;br /&gt;
[http://people.debian.org.tw/%7Eolv/surfaceflinger/surfaceflinger.pdf Slides] and [http://people.debian.org.tw/%7Eolv/surfaceflinger/demo.tar.gz demo code].&lt;br /&gt;
&lt;br /&gt;
== Building and running the OpenGL ES NDK example == &lt;br /&gt;
&lt;br /&gt;
Here&#039;s how to build and run the san-angeles application from NDK 1.6. This program demonstrates how to use a GLSurfaceView from Java along with native OpenGL calls to perform frame rendering.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cd /Volumes/android/mydroid/&lt;br /&gt;
. build/envsetup.sh &lt;br /&gt;
including vendor/aosp/vendorsetup.sh&lt;br /&gt;
lunch sdk-eng&lt;br /&gt;
&lt;br /&gt;
============================================&lt;br /&gt;
PLATFORM_VERSION_CODENAME=REL&lt;br /&gt;
PLATFORM_VERSION=1.6&lt;br /&gt;
TARGET_PRODUCT=sdk&lt;br /&gt;
TARGET_BUILD_VARIANT=eng&lt;br /&gt;
TARGET_SIMULATOR=false&lt;br /&gt;
TARGET_BUILD_TYPE=release&lt;br /&gt;
TARGET_ARCH=arm&lt;br /&gt;
HOST_ARCH=x86&lt;br /&gt;
HOST_OS=darwin&lt;br /&gt;
HOST_BUILD_TYPE=release&lt;br /&gt;
BUILD_ID=Donut&lt;br /&gt;
============================================&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First, we need to build the shared library of native code &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/work/android/android-ndk-1.6_r1/&lt;br /&gt;
build/host-setup.sh&lt;br /&gt;
make APP=san-angeles&lt;br /&gt;
&lt;br /&gt;
Android NDK: Building for application &#039;san-angeles&#039;    &lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/importgl.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/demo.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/app-android.c&lt;br /&gt;
SharedLibrary  : libsanangeles.so&lt;br /&gt;
Install        : libsanangeles.so =&amp;gt; apps/san-angeles/project/libs/armeabi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we need to make sure we can build the Java portion of the project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android update project --path apps/san-angeles/project&lt;br /&gt;
&lt;br /&gt;
Updated local.properties&lt;br /&gt;
File build.xml is too old and needs to be updated.&lt;br /&gt;
Added file apps/san-angeles/project/build.xml&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, let&#039;s build the debug release of project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd apps/san-angeles/project/&lt;br /&gt;
ant debug&lt;br /&gt;
&lt;br /&gt;
Buildfile: build.xml&lt;br /&gt;
    [setup] Project Target: Android 1.6&lt;br /&gt;
    [setup] API level: 4&lt;br /&gt;
&lt;br /&gt;
dirs:&lt;br /&gt;
     [echo] Creating output directories if needed...&lt;br /&gt;
&lt;br /&gt;
resource-src:&lt;br /&gt;
     [echo] Generating R.java / Manifest.java from the resources...&lt;br /&gt;
&lt;br /&gt;
aidl:&lt;br /&gt;
     [echo] Compiling aidl files into Java classes...&lt;br /&gt;
&lt;br /&gt;
compile:&lt;br /&gt;
    [javac] Compiling 1 source file to /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes&lt;br /&gt;
&lt;br /&gt;
dex:&lt;br /&gt;
     [echo] Converting compiled files and external libraries into bin/classes.dex...&lt;br /&gt;
&lt;br /&gt;
package-resources:&lt;br /&gt;
     [echo] Packaging resources&lt;br /&gt;
 [aaptexec] Creating full resource package...&lt;br /&gt;
&lt;br /&gt;
debug-sign:&lt;br /&gt;
&lt;br /&gt;
package:&lt;br /&gt;
[apkbuilder] Creating .DemoActivity-debug-unaligned.apk and signing it with a debug key...&lt;br /&gt;
[apkbuilder] Using keystore: /Users/joelr/.android/debug.keystore&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes.dex =&amp;gt; classes.dex&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/libs/armeabi/libsanangeles.so =&amp;gt; lib/armeabi/libsanangeles.so&lt;br /&gt;
&lt;br /&gt;
debug:&lt;br /&gt;
     [echo] Running zip align on final apk...&lt;br /&gt;
     [echo] Debug Package: bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
BUILD SUCCESSFUL&lt;br /&gt;
Total time: 1 second&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, let&#039;s install the app on the device&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adb install -r bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
1107 KB/s (13707 bytes in 0.012s)&lt;br /&gt;
	pkg: /data/local/tmp/.DemoActivity-debug.apk&lt;br /&gt;
Success&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run the app click on the &amp;quot;tab&amp;quot; at the bottom of the Android emulator screen and then on the DemoActivity icon in the list of applications. Enjoy!&lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For [http://code.google.com/p/glesquake/ Quake], GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. lunch sdk-eng &amp;amp;&amp;amp; make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Platform/2009-10-20&amp;diff=177076</id>
		<title>Platform/2009-10-20</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Platform/2009-10-20&amp;diff=177076"/>
		<updated>2009-10-20T18:23:43Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Roundtable */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;small&amp;gt;[[Platform/2009-10-13|&amp;amp;laquo; previous week]] | [[Platform|index]] | [[Platform/2009-10-27|next week &amp;amp;raquo;]]&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Notices / Schedule ===&lt;br /&gt;
&#039;&#039;&#039;[[Releases/Firefox 3.0.15|Firefox 3.0.15]] / [[Releases/Firefox_3.5.4|Firefox 3.5.4]]&#039;&#039;&#039;&lt;br /&gt;
* both releases headed to beta today (second time for 3.5.4)&lt;br /&gt;
* please work on your blockers for 3.0.16 and 3.5.5&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Firefox 3.6b1&#039;&#039;&#039;&lt;br /&gt;
* builds available&lt;br /&gt;
* in QA&lt;br /&gt;
&lt;br /&gt;
= Blocker Report =&lt;br /&gt;
See more [[Firefox/3.6|Firefox 3.6 related blocker queries]], or learn about the [[Releases/Flags|new status and blocker flags]]&lt;br /&gt;
* Release Blockers (flag: blocking1.9.2 or blocking-firefox3.6)&lt;br /&gt;
** [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=flag%3Ablocking1.9.2%2B,blocking-firefox3.6%2B 115 OPEN] (-3 w/w)&lt;br /&gt;
** [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=FIXED%20-status1.9.2%3Afixed,unaf,wont%20flag%3Ablocking1.9.2%2B,blocking-firefox3.6%2B 33 FIXED but not yet fixed on mozilla-1.9.2] (+7 w/w)&lt;br /&gt;
** [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=flag%3Ablocking1.9.2%3F,blocking-firefox3.6%3F 69 nominations] (+22 w/w)&lt;br /&gt;
** Handy charts: [http://people.mozilla.org/~mnandigama/openBlockers.html Blocker snapshots], [http://people.mozilla.org/~mnandigama/openBlockersTrend.html Blocker and Noms trends]&lt;br /&gt;
* Approvals&lt;br /&gt;
** [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=ALL%20-status1.9.2%3Afixed,unaf,wont%20flag%3Aapproval1.9.2%3F 97 requests] (+5 w/w)&lt;br /&gt;
** [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=ALL%20-status1.9.2%3Afixed,unaf,wont%20flag%3Aapproval1.9.2%2B 37 approved but not yet fixed on mozilla-1.9.2] (+3 w/w)&lt;br /&gt;
** Charts: [http://people.mozilla.org/~mnandigama/openblockersNominated.html Nominations snapshots]&lt;br /&gt;
&lt;br /&gt;
=== Browser / Front End ===&lt;br /&gt;
(Progress reports every weekend on [http://planet.firefox.com Planet Firefox])&lt;br /&gt;
* see our [[Firefox/Projects|active projects]] and get involved / &#039;&#039;&#039;propose others&#039;&#039;&#039;&lt;br /&gt;
* Namoroka/mozilla-1.9.2 front end development:&lt;br /&gt;
** [[Firefox/Projects/Per_Tab_Network_Prioritization|session restore speedup]] is the only potential change for 1.9.2 at this point, will know by end of this week&lt;br /&gt;
&lt;br /&gt;
* Axel asked about strings left to land&lt;br /&gt;
** already at string freeze, anything else is considered an exception&lt;br /&gt;
** axel says we can make limited string changes until this Friday, October 23rd&lt;br /&gt;
** beltzner to follow up in dev-planning today&lt;br /&gt;
&lt;br /&gt;
* Juan from QA expressed concern about two issues&lt;br /&gt;
** windows7 tab previews aren&#039;t working great&lt;br /&gt;
*** blockers on file, we might have to pull it out&lt;br /&gt;
** tegra OS builds are slow&lt;br /&gt;
*** being resolved with a new OS image from NVIDIA&lt;br /&gt;
&lt;br /&gt;
=== GFX Update ===&lt;br /&gt;
* [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=ALL%20priority:P1%20comp:gfx,imagelib,graphics%20flag:blocking1.9.2%2B%20-status1.9.2:fixed,unaffected,wontfix 0 beta blockers];  [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=ALL%20comp:gfx,imagelib,graphics%20flag:blocking1.9.2%2B%20-status1.9.2:fixed,unaffected,wontfix 4 1.9.2 blockers].&lt;br /&gt;
** The only one that worries me is the NVIDIA Windows CE image corruption bug, {{bug|500200}}, which we have not been able to make progress on, and for which we suspect a driver bug.&lt;br /&gt;
* Bas has made a lot of progress on the DirectWrite font backend for Windows 7. There are lots of screenshots in {{bug|517642}}. There&#039;s still a ways to go before this will be ready for prime time, but we&#039;re getting great results.&lt;br /&gt;
* Jim has been having trouble reproducing a drag-and-drop cursor flickering problem on Windows. If you have seen cursor flickering, please weigh in on {{bug|521966}}.&lt;br /&gt;
* The WebGL standard has been submitted to the Khronos board for intellectual property considerations. This will be a 45-day process, after which the spec will be released for public review.&lt;br /&gt;
&lt;br /&gt;
=== Layout Update ===&lt;br /&gt;
&lt;br /&gt;
* Blocker report&lt;br /&gt;
** 14 Layout&lt;br /&gt;
*** 2 fixed on trunk and need landing&lt;br /&gt;
*** Some others need review&lt;br /&gt;
*** A handful of background-image invalidation/repaint issues&lt;br /&gt;
*** Need triage, but nothing scary on the list&lt;br /&gt;
*** Silverlight 3 doesn&#039;t work, Microsoft unresponsive in Bugzilla&lt;br /&gt;
** 1 Video/audio, fixed on trunk and needs branch landing&lt;br /&gt;
* Frame poisoning mitigated a newly discovered bug (yay)&lt;br /&gt;
* Ongoing animation improvements, can animate &#039;opacity&#039; now (dholbert)&lt;br /&gt;
* New Ogg index code based on Ogg Skeleton track (cpearce)&lt;br /&gt;
* Ogg decoder rewrite grinding through tests (doublec)&lt;br /&gt;
* Removed media element &amp;quot;load&amp;quot; event and NETWORK_LOADING state on trunk and branch&lt;br /&gt;
* Discuss changing CSS gradient syntax for 1.9.2&lt;br /&gt;
* jdaggett and jfkthame prepping for AtypI&lt;br /&gt;
&lt;br /&gt;
=== Content Update ===&lt;br /&gt;
* 24 1.9.1 blockers left.&lt;br /&gt;
* Investigating how much and where to focus on websocket/HyBi protocol spec work (Jason and Jonas)&lt;br /&gt;
* (josh) We have an accepted spec for Linux plugin accessibility and Novell is working on a patch for 1.9.3. Works with out-of-process plugins.&lt;br /&gt;
** https://wiki.mozilla.org/Plugins:NativeAccessibility&lt;br /&gt;
* Multi-file select patch done, but needs testing before ready (Jonas)&lt;br /&gt;
* HTML5 parser update (hsivonen)&lt;br /&gt;
&lt;br /&gt;
=== Platform-specific Support Update ===&lt;br /&gt;
* (josh) Still waiting on sqlite library conflict resolution ({{bug|513747}}) so we can produce 64-bit Mac OS X builds without patches and set up a tinderbox. This also blocks running mochitests on 10.6.&lt;br /&gt;
* (smichaud) 1.9.2/JEP update -- old bugs fixed, new bugs found:&lt;br /&gt;
** {{bug|513979}} (Disable Java setting not preserved when switching from FF 3.5 to 3.6):&lt;br /&gt;
*** Fixed and landed, in beta1.&lt;br /&gt;
** {{bug|521818}} (Current plugin instance not destroyed when disabling Java):&lt;br /&gt;
*** Fixed and landed, not in beta1.&lt;br /&gt;
** {{bug|522962}} (Applet needs to be reloaded after switching to/from full screen mode):&lt;br /&gt;
*** Needs to be fixed in JEP, probably not a blocker.&lt;br /&gt;
** {{bug|523129}} (Java&#039;s AppletContext.showDocument() doesn&#039;t work on 1.9.2 branch):&lt;br /&gt;
*** Patch available, blocker.&lt;br /&gt;
&lt;br /&gt;
=== JS ===&lt;br /&gt;
&lt;br /&gt;
* Continuing allocation performance improvements&lt;br /&gt;
* recursive function changes&lt;br /&gt;
* identified major source of browser/shell perf delta: wrappers / security checks. About 15% on SunSpider.&lt;br /&gt;
&lt;br /&gt;
=== Startup Performance ===&lt;br /&gt;
&lt;br /&gt;
Remeasuring 3.5 cold startup on WinXP is giving roller-coaster numbers, ups and downs in the &amp;gt;20% range between builds with changes that are seemingly innocuous. Focus this week is on figuring out how to get stable numbers there.&lt;br /&gt;
&lt;br /&gt;
At all ranges in the graph, the 3.5 WinXP cold startup numbers are all showing a regression in 3.6/3.7... again. I&#039;ll re-open that bug and work on figuring out a regression range. However, this is blocked on getting reliable numbers out of 3.5, see above.&lt;br /&gt;
&lt;br /&gt;
Highlights from the [http://autonome.wordpress.com/2009/10/17/firefox-startup-performance-weekly-summary-6/ weekly update post]:&lt;br /&gt;
&lt;br /&gt;
* Ben Hsieh’s work to improve fastload cache invalidation landed in {{bug|511761}}, with a 3% win on warm startup of WinXP.&lt;br /&gt;
* Alfred Kayser landed {{bug|511754}}, which improves JAR file reading efficiency.&lt;br /&gt;
* Rob Strong closed {{bug|521956}} and started some cleanup of nsUpdateService, further reducing the size of it for {{bug|311965}}.&lt;br /&gt;
* Drew has a patch up for {{bug|506814}}, getting rid of ChangeGetPersistentDescriptor/SetPersistentDescriptor on Mac, needs review Josh.&lt;br /&gt;
&lt;br /&gt;
Join us on IRC in [http://irc.mozilla.org/#startup #startup].&lt;br /&gt;
&lt;br /&gt;
=== Security ===&lt;br /&gt;
Lightweight themes security review today at 12:30 (PDT).&lt;br /&gt;
&lt;br /&gt;
Other [[Firefox3.6/Security|pending reviews]]&lt;br /&gt;
&lt;br /&gt;
=== Electrolysis ===&lt;br /&gt;
&lt;br /&gt;
* Plugins:&lt;br /&gt;
** working towards getting stuff landed in mozilla-central, preffed off. See {{bug|523904}} for dependencies.&lt;br /&gt;
** Windowless impl work continues, basic Windows support has been reviewed, needs to land.&lt;br /&gt;
** NPRuntime basically complete, some edge cases to clean up but nothing that renders it inoperable.&lt;br /&gt;
&lt;br /&gt;
* Tabs&lt;br /&gt;
** Focusing on getting a Fennec demo working.&lt;br /&gt;
** Smaug has been dealing with focus and embedding issues which should make keyboard events work properly.&lt;br /&gt;
** bsmedberg working on removing assumptions about browsers having docshells&lt;br /&gt;
** Probably need to remote some basic events such as MozAfterPaint in order for the Fennec tilebrowser to work correctly&lt;br /&gt;
&lt;br /&gt;
* Necko&lt;br /&gt;
** close to having our full set of necko xpcshell unit tests running in content process--researching failures/hangs.&lt;br /&gt;
&lt;br /&gt;
=== Tree Management ===&lt;br /&gt;
* Cold Ts on Mac and Linux turned on last week&lt;br /&gt;
* Turned on &#039;make check&#039; tests on optimized and debug builds on trunk and project branches.&lt;br /&gt;
* Turned on valgrind tests on debug builds on linux tracemonkey&lt;br /&gt;
* 7 new mac slaves added to build/test pool today, 2 xserves + 1 mini coming soon&lt;br /&gt;
* Proposing to land split-mochitests on Thursday morning.&lt;br /&gt;
&lt;br /&gt;
=== Roundtable ===&lt;br /&gt;
* Plan for Websockets patch? [roc]&lt;br /&gt;
* Minor update for 1.9.2? [roc]&lt;br /&gt;
* Firebug status&lt;br /&gt;
* [https://wiki.mozilla.org/User:Joel_Reymont/Android_Notes#Can_Android_run_a_completely_native_app.3F Can we run a completely native app on Android?] Join us on IRC in [http://irc.mozilla.org/#android #android].&lt;br /&gt;
* interface changes between now and mozilla-1.9.2 release? [beltzner]&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Platform/2009-10-20&amp;diff=177061</id>
		<title>Platform/2009-10-20</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Platform/2009-10-20&amp;diff=177061"/>
		<updated>2009-10-20T18:14:13Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Roundtable */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;small&amp;gt;[[Platform/2009-10-13|&amp;amp;laquo; previous week]] | [[Platform|index]] | [[Platform/2009-10-27|next week &amp;amp;raquo;]]&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Notices / Schedule ===&lt;br /&gt;
&#039;&#039;&#039;[[Releases/Firefox 3.0.15|Firefox 3.0.15]] / [[Releases/Firefox_3.5.4|Firefox 3.5.4]]&#039;&#039;&#039;&lt;br /&gt;
* both releases headed to beta today (second time for 3.5.4)&lt;br /&gt;
* please work on your blockers for 3.0.16 and 3.5.5&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Firefox 3.6b1&#039;&#039;&#039;&lt;br /&gt;
* builds available&lt;br /&gt;
* in QA&lt;br /&gt;
&lt;br /&gt;
= Blocker Report =&lt;br /&gt;
See more [[Firefox/3.6|Firefox 3.6 related blocker queries]], or learn about the [[Releases/Flags|new status and blocker flags]]&lt;br /&gt;
* Release Blockers (flag: blocking1.9.2 or blocking-firefox3.6)&lt;br /&gt;
** [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=flag%3Ablocking1.9.2%2B,blocking-firefox3.6%2B 115 OPEN] (-3 w/w)&lt;br /&gt;
** [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=FIXED%20-status1.9.2%3Afixed,unaf,wont%20flag%3Ablocking1.9.2%2B,blocking-firefox3.6%2B 33 FIXED but not yet fixed on mozilla-1.9.2] (+7 w/w)&lt;br /&gt;
** [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=flag%3Ablocking1.9.2%3F,blocking-firefox3.6%3F 69 nominations] (+22 w/w)&lt;br /&gt;
** Handy charts: [http://people.mozilla.org/~mnandigama/openBlockers.html Blocker snapshots], [http://people.mozilla.org/~mnandigama/openBlockersTrend.html Blocker and Noms trends]&lt;br /&gt;
* Approvals&lt;br /&gt;
** [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=ALL%20-status1.9.2%3Afixed,unaf,wont%20flag%3Aapproval1.9.2%3F 97 requests] (+5 w/w)&lt;br /&gt;
** [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=ALL%20-status1.9.2%3Afixed,unaf,wont%20flag%3Aapproval1.9.2%2B 37 approved but not yet fixed on mozilla-1.9.2] (+3 w/w)&lt;br /&gt;
** Charts: [http://people.mozilla.org/~mnandigama/openblockersNominated.html Nominations snapshots]&lt;br /&gt;
&lt;br /&gt;
=== Browser / Front End ===&lt;br /&gt;
(Progress reports every weekend on [http://planet.firefox.com Planet Firefox])&lt;br /&gt;
* see our [[Firefox/Projects|active projects]] and get involved / &#039;&#039;&#039;propose others&#039;&#039;&#039;&lt;br /&gt;
* Namoroka/mozilla-1.9.2 front end development:&lt;br /&gt;
&lt;br /&gt;
=== GFX Update ===&lt;br /&gt;
* [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=ALL%20priority:P1%20comp:gfx,imagelib,graphics%20flag:blocking1.9.2%2B%20-status1.9.2:fixed,unaffected,wontfix 0 beta blockers];  [https://bugzilla.mozilla.org/buglist.cgi?quicksearch=ALL%20comp:gfx,imagelib,graphics%20flag:blocking1.9.2%2B%20-status1.9.2:fixed,unaffected,wontfix 4 1.9.2 blockers].&lt;br /&gt;
** The only one that worries me is the NVIDIA Windows CE image corruption bug, {{bug|500200}}, which we have not been able to make progress on, and for which we suspect a driver bug.&lt;br /&gt;
* Bas has made a lot of progress on the DirectWrite font backend for Windows 7. There are lots of screenshots in {{bug|517642}}. There&#039;s still a ways to go before this will be ready for prime time, but we&#039;re getting great results.&lt;br /&gt;
* Jim has been having trouble reproducing a drag-and-drop cursor flickering problem on Windows. If you have seen cursor flickering, please weigh in on {{bug|521966}}.&lt;br /&gt;
* The WebGL standard has been submitted to the Khronos board for intellectual property considerations. This will be a 45-day process, after which the spec will be released for public review.&lt;br /&gt;
&lt;br /&gt;
=== Layout Update ===&lt;br /&gt;
&lt;br /&gt;
* Blocker report&lt;br /&gt;
** 18 Layout&lt;br /&gt;
*** 4 fixed on trunk and need landing&lt;br /&gt;
*** Some others need review&lt;br /&gt;
*** Need triage, but nothing scary on the list&lt;br /&gt;
*** Silverlight 3 doesn&#039;t work, Microsoft unresponsive in Bugzilla&lt;br /&gt;
** 5 Video/audio, all fixed on trunk and need branch landing&lt;br /&gt;
* Frame poisoning mitigated a newly discovered bug (yay)&lt;br /&gt;
* Ongoing animation improvements, can animate &#039;opacity&#039; now (dholbert)&lt;br /&gt;
* New Ogg index code based on Ogg Skeleton track (cpearce)&lt;br /&gt;
* Ogg decoder rewrite grinding through tests (doublec)&lt;br /&gt;
* Removed media element &amp;quot;load&amp;quot; event and NETWORK_LOADING state on trunk and branch&lt;br /&gt;
* Discuss changing CSS gradient syntax for 1.9.2&lt;br /&gt;
* jdaggett and jfkthame prepping for AtypI&lt;br /&gt;
&lt;br /&gt;
=== Content Update ===&lt;br /&gt;
* 24 1.9.1 blockers left.&lt;br /&gt;
* Investigating how much and where to focus on websocket/HiBy protocol spec work (Jason and Jonas)&lt;br /&gt;
* (josh) We have an accepted spec for Linux plugin accessibility and Novell is working on a patch for 1.9.3. Works with out-of-process plugins.&lt;br /&gt;
** https://wiki.mozilla.org/Plugins:NativeAccessibility&lt;br /&gt;
* Multi-file select patch done, but needs testing before ready (Jonas)&lt;br /&gt;
* HTML5 parser update (hsivonen)&lt;br /&gt;
&lt;br /&gt;
=== Platform-specific Support Update ===&lt;br /&gt;
* (josh) Still waiting on sqlite library conflict resolution ({{bug|513747}}) so we can produce 64-bit Mac OS X builds without patches and set up a tinderbox. This also blocks running mochitests on 10.6.&lt;br /&gt;
* (smichaud) 1.9.2/JEP update -- old bugs fixed, new bugs found:&lt;br /&gt;
** {{bug|513979}} (Disable Java setting not preserved when switching from FF 3.5 to 3.6):&lt;br /&gt;
*** Fixed and landed, in beta1.&lt;br /&gt;
** {{bug|521818}} (Current plugin instance not destroyed when disabling Java):&lt;br /&gt;
*** Fixed and landed, not in beta1.&lt;br /&gt;
** {{bug|522962}} (Applet needs to be reloaded after switching to/from full screen mode):&lt;br /&gt;
*** Needs to be fixed in JEP, probably not a blocker.&lt;br /&gt;
** {{bug|523129}} (Java&#039;s AppletContext.showDocument() doesn&#039;t work on 1.9.2 branch):&lt;br /&gt;
*** Patch available.&lt;br /&gt;
&lt;br /&gt;
=== JS ===&lt;br /&gt;
&lt;br /&gt;
* Continuing allocation performance improvements&lt;br /&gt;
* recursive function changes&lt;br /&gt;
* identified major source of browser/shell perf delta: wrappers / security checks. About 15% on SunSpider.&lt;br /&gt;
&lt;br /&gt;
=== Startup Performance ===&lt;br /&gt;
&lt;br /&gt;
Remeasuring 3.5 cold startup on WinXP is giving roller-coaster numbers, ups and downs in the &amp;gt;20% range between builds with changes that are seemingly innocuous. Focus this week is on figuring out how to get stable numbers there.&lt;br /&gt;
&lt;br /&gt;
At all ranges in the graph, the 3.5 WinXP cold startup numbers are all showing a regression in 3.6/3.7... again. I&#039;ll re-open that bug and work on figuring out a regression range. However, this is blocked on getting reliable numbers out of 3.5, see above.&lt;br /&gt;
&lt;br /&gt;
Highlights from the [http://autonome.wordpress.com/2009/10/17/firefox-startup-performance-weekly-summary-6/ weekly update post]:&lt;br /&gt;
&lt;br /&gt;
* Ben Hsieh’s work to improve fastload cache invalidation landed in {{bug|511761}}, with a 3% win on warm startup of WinXP.&lt;br /&gt;
* Alfred Kayser landed {{bug|511754}}, which improves JAR file reading efficiency.&lt;br /&gt;
* Rob Strong closed {{bug|521956}} and started some cleanup of nsUpdateService, further reducing the size of it for {{bug|311965}}.&lt;br /&gt;
* Drew has a patch up for {{bug|506814}}, getting rid of ChangeGetPersistentDescriptor/SetPersistentDescriptor on Mac, needs review Josh.&lt;br /&gt;
&lt;br /&gt;
Join us on IRC in [http://irc.mozilla.org/#startup #startup].&lt;br /&gt;
&lt;br /&gt;
=== Security ===&lt;br /&gt;
&lt;br /&gt;
=== Electrolysis ===&lt;br /&gt;
&lt;br /&gt;
* Plugins:&lt;br /&gt;
** working towards getting stuff landed in mozilla-central, preffed off. See {{bug|523904}} for dependencies.&lt;br /&gt;
** Windowless impl work continues, basic Windows support has been reviewed, needs to land.&lt;br /&gt;
** NPRuntime basically complete, some edge cases to clean up but nothing that renders it inoperable.&lt;br /&gt;
&lt;br /&gt;
* Tabs&lt;br /&gt;
** Focusing on getting a Fennec demo working.&lt;br /&gt;
** Smaug has been dealing with focus and embedding issues which should make keyboard events work properly.&lt;br /&gt;
** bsmedberg working on removing assumptions about browsers having docshells&lt;br /&gt;
** Probably need to remote some basic events such as MozAfterPaint in order for the Fennec tilebrowser to work correctly&lt;br /&gt;
&lt;br /&gt;
* Necko&lt;br /&gt;
** close to having our full set of necko xpcshell unit tests running in content process--researching failures/hangs.&lt;br /&gt;
&lt;br /&gt;
=== Tree Management ===&lt;br /&gt;
* Cold Ts on Mac and Linux turned on last week&lt;br /&gt;
* Turned on &#039;make check&#039; tests on optimized and debug builds on trunk and project branches.&lt;br /&gt;
* Turned on valgrind tests on debug builds on linux tracemonkey&lt;br /&gt;
* 8 new mac slaves added to build/test pool today, 2 xserves coming soon&lt;br /&gt;
* Proposing to land split-mochitests on Thursday morning.&lt;br /&gt;
&lt;br /&gt;
=== Roundtable ===&lt;br /&gt;
* Plan for Websockets patch? [roc]&lt;br /&gt;
* Minor update for 1.9.2? [roc]&lt;br /&gt;
* Firebug status&lt;br /&gt;
* [https://wiki.mozilla.org/User:Joel_Reymont/Android_Notes#Can_Android_run_a_completely_native_app.3F Can we run a completely native app on Android?]&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=176953</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=176953"/>
		<updated>2009-10-20T17:29:37Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Can Android run a completely native app? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 12, 2009 ==&lt;br /&gt;
&lt;br /&gt;
Via Chris Lord...&lt;br /&gt;
&lt;br /&gt;
The [http://hg.mozilla.org/incubator/offscreen headless branch of Mozilla that we work on] renders to system memory and it is up to the embedder to get this to a texture however they like. We have our own embedding library that uses this with Clutter&lt;br /&gt;
[http://git.clutter-project.org/?r=clutter-mozembed clutter-mozembed] and we just upload each changed region to the texture.&lt;br /&gt;
&lt;br /&gt;
A possible speed-up is to use a shared memory pixmap and texture-from-pixmap (or whatever the platform&#039;s equivalent is), which&lt;br /&gt;
would remove the need to copy from system to video memory.&lt;br /&gt;
&lt;br /&gt;
I wrote a (now out-dated, but still relevant) [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten guide on building the Moblin browser components] on my blog. There&#039;s also a [http://chrislord.net/files/moz-headless-screenshot.c short demo application I wrote] that just uses mozilla-headless alone to take a screenshot of a web-page. &lt;br /&gt;
&lt;br /&gt;
Unfortunately, there is no documentation beyond the standard Mozilla documentation and the source-code (and the above-mentioned links).&lt;br /&gt;
&lt;br /&gt;
I think the easiest way to port Firefox to android would be to write an android-backend (which could well be based on our headless backend) - I didn&#039;t think that the Android native development kit was fully featured enough to allow something like this though?&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
You can&#039;t run Firefox with the headless backend as it is, it&#039;s designed to be embedded and for libxul to be used. The headless backend is also heavily dependent on GLib (for the main loop, signals and idle handlers).&lt;br /&gt;
&lt;br /&gt;
If you wanted to run Firefox, you&#039;d have to write a new backend, or modify an existing one, to provide the application framework. In the gtk2 and headless backends, this is GLib-based. The Gtk2 backend creates a GtkWindow and that is how the user sees and interacts with the application. On the headless backend, there is no visible window. It can only be used for embedding via libxul.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
Chris has a [http://chrislord.net/files/fosdem-09-slides.odp presentation] that explains the headless branch a bit and [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten instructions on how to build it].&lt;br /&gt;
&lt;br /&gt;
--- &lt;br /&gt;
&lt;br /&gt;
There&#039;s an [https://bugzilla.mozilla.org/show_bug.cgi?id=446591 existing bug] that deals with headless UI.&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Can Android run a completely native app? ==&lt;br /&gt;
&lt;br /&gt;
According to  [http://sites.google.com/site/io/anatomy--physiology-of-an-android Anatomy and physiology] and [http://developer.android.com/guide/topics/fundamentals.html Android Fundamentals], each Android process has its own Java virtual machine (VM), so application code runs in isolation from the code of all other applications. &lt;br /&gt;
&lt;br /&gt;
Android processes (Java VMs) communicate with the Home App and various system services via the [http://en.wikipedia.org/wiki/OpenBinder Binder IPC] described using [http://developer.android.com/guide/developing/tools/aidl.html Android Interface Definition Language (AIDL)].&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;Home Application&#039;&#039; (Launcher) is the app that displays the Android desktop and allows the [http:///Volumes/android/mydroid/frameworks/base/core/java/android/app/LauncherActivity.java launching of other apps] by clicking on their icons. &lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;activity&#039;&#039; presents a visual user interface for one focused endeavor the user can undertake. For example, an activity might present a list of menu items users can choose from or it might display photographs along with their captions. A text messaging application might have one activity that shows a list of contacts to send messages to, a second activity to write the message to the chosen contact, and other activities to review old messages or change settings.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;task&#039;&#039; is a group of related activities. May include activities from other apps, running in other processes, e.g. map viewer. A task has an activity stack. &lt;br /&gt;
&lt;br /&gt;
Any given activity  &lt;br /&gt;
&lt;br /&gt;
* Has a content view that is created using a layout resource.&lt;br /&gt;
* Can be floating or embedded inside another activity.&lt;br /&gt;
* Has a pause callback invoked when the user is leaving the activity.&lt;br /&gt;
* Is visible when it&#039;s at the top of the stack for the current task.&lt;br /&gt;
* Is paused when there&#039;s another activity on top of it but remains visible. It has lost focus but remains completely alive and attached to the window manager but can be killed in low memory conditions.&lt;br /&gt;
* Is stopped when it&#039;s completely obscured by another activity. The window is hidden and activity will be killed when memory is needed elsewhere. &lt;br /&gt;
* Has a finish callback that may be called when the activity is being evicted from memory.&lt;br /&gt;
* Generates a thumbnail of the activity via a callback that&#039;s called before pausing.&lt;br /&gt;
* Receives trackball and key events via callbacks.&lt;br /&gt;
&lt;br /&gt;
When an app icon is clicked, the Home app uses the package manager to retrive app info and package it into an [http:///Volumes/android/mydroid/frameworks/base/core/java/android/content/Intent.java intent], an asynchronous message with information necessary to start a given activity. The Home app then uses startActivity, a method of Context to launch the activity. [http:///Volumes/android/mydroid/frameworks/base/core/java/android/content/Context.java Context is an abstract class] whose implementation is provided by the Android system.&lt;br /&gt;
&lt;br /&gt;
The launch request is sent via the Binder IPC to the [http:///Volumes/android/mydroid/frameworks/base/services/java/com/android/server/am/ActivityManagerService.java Activity Manager Service] which uses the [http:///Volumes/android/mydroid/frameworks/base/core/java/android/os/Process.java Process] class to start an [http:///Volumes/android/mydroid/frameworks/base/core/java/android/app/ActivityThread.java Activity Thread] in a new instance of the Dalvik Java VM via the [http:///Volumes/android/mydroid//Volumes/android/mydroid/system/core/libcutils/zygote.c Zygote].&lt;br /&gt;
&lt;br /&gt;
The mechanism above assumes Java is used to implement activities. For example, the first non-option argument to Zygote should be a class name in the system class path. Also, [http://developer.android.com/guide/developing/tools/aidl.html aidl command-line tool] only generates Java code for Binder IPCs. &lt;br /&gt;
&lt;br /&gt;
While I&#039;m confident that I could write a native application that plugs into the Android event stream as well as the activity, window, etc. managers, doing so would require adding C++ code generation to the &#039;&#039;aidl tool&#039;&#039; and implementing the portion of the Android Java SDK that deals with the activity life cycle. &lt;br /&gt;
&lt;br /&gt;
Still, it will not be possible to launch a native app from the Home app due to the Java assumptions in the core launching mechanism, so a Java shim will be required. There may be a great deal of flexibility in running a completely native app since, for example, OpenGL ES is not required and the screen (surface) buffer can be written to directly. &lt;br /&gt;
&lt;br /&gt;
Another alternative is to let the Java shim handle act as an invisible &#039;&#039;activity&#039;&#039; that uses the NDK to pass events to native code running in a shared library. OpenGL ES will be required in the latter case to write to a pre-configured screen context.&lt;br /&gt;
&lt;br /&gt;
== Sample external application Makefile ==&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you can build your own native apps without being shoehorned into the Android SDK build structure. I got this by massaging the output of &#039;&#039;make showcommands&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SDK := /Volumes/android/mydroid&lt;br /&gt;
TOOLCHAIN := $(SDK)/prebuilt/darwin-x86/toolchain/arm-eabi-4.2.1&lt;br /&gt;
ABILIB := $(TOOLCHAIN)/lib/gcc/arm-eabi/4.2.1/&lt;br /&gt;
BIN := $(TOOLCHAIN)/bin&lt;br /&gt;
C++ := $(BIN)/arm-eabi-g++&lt;br /&gt;
CC := $(BIN)/arm-eabi-gcc&lt;br /&gt;
&lt;br /&gt;
INCLUDE := \&lt;br /&gt;
  -I$(SDK)/system/core/include \&lt;br /&gt;
  -I$(SDK)/hardware/libhardware/include \&lt;br /&gt;
  -I$(SDK)/hardware/libhardware_legacy/include \&lt;br /&gt;
  -I$(SDK)/hardware/ril/include \&lt;br /&gt;
  -I$(SDK)/dalvik/libnativehelper/include \&lt;br /&gt;
  -I$(SDK)/frameworks/base/include \&lt;br /&gt;
  -I$(SDK)/frameworks/base/opengl/include \&lt;br /&gt;
  -I$(SDK)/external/skia/include \&lt;br /&gt;
  -I$(SDK)/out/target/product/generic/obj/include \&lt;br /&gt;
  -I$(SDK)/bionic/libc/arch-arm/include \&lt;br /&gt;
  -I$(SDK)/bionic/libc/include \&lt;br /&gt;
  -I$(SDK)/bionic/libstdc++/include \&lt;br /&gt;
  -I$(SDK)/bionic/libc/kernel/common \&lt;br /&gt;
  -I$(SDK)/bionic/libc/kernel/arch-arm \&lt;br /&gt;
  -I$(SDK)/bionic/libm/include \&lt;br /&gt;
  -I$(SDK)/bionic/libm/include/arch/arm \&lt;br /&gt;
  -I$(SDK)/bionic/libthread_db/include \&lt;br /&gt;
  -I$(SDK)/frameworks/base/cmds/demo \&lt;br /&gt;
  -I$(SDK)/system/core/include/arch/linux-arm \&lt;br /&gt;
  -include $(SDK)/system/core/include/arch/linux-arm/AndroidConfig.h \&lt;br /&gt;
  $(NULL)&lt;br /&gt;
  &lt;br /&gt;
CFLAGS = \&lt;br /&gt;
  -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5TE__ -DANDROID \&lt;br /&gt;
  -DSK_RELEASE -DNDEBUG -UDEBUG \&lt;br /&gt;
  -mthumb -mthumb-interwork -msoft-float -march=armv5te -mtune=xscale \&lt;br /&gt;
  -fpic -fno-exceptions -ffunction-sections -funwind-tables -fstack-protector \&lt;br /&gt;
  -fno-short-enums -fmessage-length=0 -finline-functions -fno-inline-functions-called-once \&lt;br /&gt;
  -fgcse-after-reload -frerun-cse-after-loop -frename-registers -fvisibility-inlines-hidden \&lt;br /&gt;
  -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -fno-rtti \&lt;br /&gt;
  -W -Wall -Wno-multichar -Wno-unused -Werror=return-type -Wstrict-aliasing=2 \&lt;br /&gt;
  -Wnon-virtual-dtor -Werror=return-type \&lt;br /&gt;
  -MD -Os -g \&lt;br /&gt;
  $(NULL)&lt;br /&gt;
 &lt;br /&gt;
LIBDIR := $(SDK)/out/target/product/generic/obj/lib&lt;br /&gt;
&lt;br /&gt;
LIBS := -lui -llog -lutils -lc -lstdc++ -lm $(LIBDIR)/crtbegin_dynamic.o &lt;br /&gt;
  &lt;br /&gt;
LDFLAGS := \&lt;br /&gt;
  -nostdlib -Bdynamic -Wl,--no-undefined -Wl,-T,$(SDK)/build/core/armelf.x \&lt;br /&gt;
  -Wl,-dynamic-linker,$(SDK)/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc \&lt;br /&gt;
  -L$(LIBDIR) -Wl,-rpath-link=$(LIBDIR) \&lt;br /&gt;
  $(NULL)&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
all: demo&lt;br /&gt;
&lt;br /&gt;
demo: surfaceflinger.o demo.o&lt;br /&gt;
	$(C++) $(LDFLAGS) -o demo $(LIBS) surfaceflinger.o demo.o \&lt;br /&gt;
		$(ABILIB)/interwork/libgcc.a $(LIBDIR)/crtend_android.o&lt;br /&gt;
&lt;br /&gt;
surfaceflinger.o: &lt;br /&gt;
	$(C++) $(INCLUDE) -c $(CFLAGS) surfaceflinger.cpp&lt;br /&gt;
&lt;br /&gt;
demo.o:&lt;br /&gt;
	$(CC) $(INCLUDE) -c $(CFLAGS) demo.c&lt;br /&gt;
&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f demo *.o	&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction to the Android Window System ==&lt;br /&gt;
&lt;br /&gt;
[http://people.debian.org.tw/%7Eolv/surfaceflinger/surfaceflinger.pdf Slides] and [http://people.debian.org.tw/%7Eolv/surfaceflinger/demo.tar.gz demo code].&lt;br /&gt;
&lt;br /&gt;
== Building and running the OpenGL ES NDK example == &lt;br /&gt;
&lt;br /&gt;
Here&#039;s how to build and run the san-angeles application from NDK 1.6. This program demonstrates how to use a GLSurfaceView from Java along with native OpenGL calls to perform frame rendering.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cd /Volumes/android/mydroid/&lt;br /&gt;
. build/envsetup.sh &lt;br /&gt;
including vendor/aosp/vendorsetup.sh&lt;br /&gt;
lunch sdk-eng&lt;br /&gt;
&lt;br /&gt;
============================================&lt;br /&gt;
PLATFORM_VERSION_CODENAME=REL&lt;br /&gt;
PLATFORM_VERSION=1.6&lt;br /&gt;
TARGET_PRODUCT=sdk&lt;br /&gt;
TARGET_BUILD_VARIANT=eng&lt;br /&gt;
TARGET_SIMULATOR=false&lt;br /&gt;
TARGET_BUILD_TYPE=release&lt;br /&gt;
TARGET_ARCH=arm&lt;br /&gt;
HOST_ARCH=x86&lt;br /&gt;
HOST_OS=darwin&lt;br /&gt;
HOST_BUILD_TYPE=release&lt;br /&gt;
BUILD_ID=Donut&lt;br /&gt;
============================================&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First, we need to build the shared library of native code &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/work/android/android-ndk-1.6_r1/&lt;br /&gt;
build/host-setup.sh&lt;br /&gt;
make APP=san-angeles&lt;br /&gt;
&lt;br /&gt;
Android NDK: Building for application &#039;san-angeles&#039;    &lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/importgl.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/demo.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/app-android.c&lt;br /&gt;
SharedLibrary  : libsanangeles.so&lt;br /&gt;
Install        : libsanangeles.so =&amp;gt; apps/san-angeles/project/libs/armeabi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we need to make sure we can build the Java portion of the project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android update project --path apps/san-angeles/project&lt;br /&gt;
&lt;br /&gt;
Updated local.properties&lt;br /&gt;
File build.xml is too old and needs to be updated.&lt;br /&gt;
Added file apps/san-angeles/project/build.xml&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, let&#039;s build the debug release of project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd apps/san-angeles/project/&lt;br /&gt;
ant debug&lt;br /&gt;
&lt;br /&gt;
Buildfile: build.xml&lt;br /&gt;
    [setup] Project Target: Android 1.6&lt;br /&gt;
    [setup] API level: 4&lt;br /&gt;
&lt;br /&gt;
dirs:&lt;br /&gt;
     [echo] Creating output directories if needed...&lt;br /&gt;
&lt;br /&gt;
resource-src:&lt;br /&gt;
     [echo] Generating R.java / Manifest.java from the resources...&lt;br /&gt;
&lt;br /&gt;
aidl:&lt;br /&gt;
     [echo] Compiling aidl files into Java classes...&lt;br /&gt;
&lt;br /&gt;
compile:&lt;br /&gt;
    [javac] Compiling 1 source file to /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes&lt;br /&gt;
&lt;br /&gt;
dex:&lt;br /&gt;
     [echo] Converting compiled files and external libraries into bin/classes.dex...&lt;br /&gt;
&lt;br /&gt;
package-resources:&lt;br /&gt;
     [echo] Packaging resources&lt;br /&gt;
 [aaptexec] Creating full resource package...&lt;br /&gt;
&lt;br /&gt;
debug-sign:&lt;br /&gt;
&lt;br /&gt;
package:&lt;br /&gt;
[apkbuilder] Creating .DemoActivity-debug-unaligned.apk and signing it with a debug key...&lt;br /&gt;
[apkbuilder] Using keystore: /Users/joelr/.android/debug.keystore&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes.dex =&amp;gt; classes.dex&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/libs/armeabi/libsanangeles.so =&amp;gt; lib/armeabi/libsanangeles.so&lt;br /&gt;
&lt;br /&gt;
debug:&lt;br /&gt;
     [echo] Running zip align on final apk...&lt;br /&gt;
     [echo] Debug Package: bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
BUILD SUCCESSFUL&lt;br /&gt;
Total time: 1 second&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, let&#039;s install the app on the device&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adb install -r bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
1107 KB/s (13707 bytes in 0.012s)&lt;br /&gt;
	pkg: /data/local/tmp/.DemoActivity-debug.apk&lt;br /&gt;
Success&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run the app click on the &amp;quot;tab&amp;quot; at the bottom of the Android emulator screen and then on the DemoActivity icon in the list of applications. Enjoy!&lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For [http://code.google.com/p/glesquake/ Quake], GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. lunch sdk-eng &amp;amp;&amp;amp; make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=176949</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=176949"/>
		<updated>2009-10-20T17:23:24Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Android Notes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 12, 2009 ==&lt;br /&gt;
&lt;br /&gt;
Via Chris Lord...&lt;br /&gt;
&lt;br /&gt;
The [http://hg.mozilla.org/incubator/offscreen headless branch of Mozilla that we work on] renders to system memory and it is up to the embedder to get this to a texture however they like. We have our own embedding library that uses this with Clutter&lt;br /&gt;
[http://git.clutter-project.org/?r=clutter-mozembed clutter-mozembed] and we just upload each changed region to the texture.&lt;br /&gt;
&lt;br /&gt;
A possible speed-up is to use a shared memory pixmap and texture-from-pixmap (or whatever the platform&#039;s equivalent is), which&lt;br /&gt;
would remove the need to copy from system to video memory.&lt;br /&gt;
&lt;br /&gt;
I wrote a (now out-dated, but still relevant) [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten guide on building the Moblin browser components] on my blog. There&#039;s also a [http://chrislord.net/files/moz-headless-screenshot.c short demo application I wrote] that just uses mozilla-headless alone to take a screenshot of a web-page. &lt;br /&gt;
&lt;br /&gt;
Unfortunately, there is no documentation beyond the standard Mozilla documentation and the source-code (and the above-mentioned links).&lt;br /&gt;
&lt;br /&gt;
I think the easiest way to port Firefox to android would be to write an android-backend (which could well be based on our headless backend) - I didn&#039;t think that the Android native development kit was fully featured enough to allow something like this though?&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
You can&#039;t run Firefox with the headless backend as it is, it&#039;s designed to be embedded and for libxul to be used. The headless backend is also heavily dependent on GLib (for the main loop, signals and idle handlers).&lt;br /&gt;
&lt;br /&gt;
If you wanted to run Firefox, you&#039;d have to write a new backend, or modify an existing one, to provide the application framework. In the gtk2 and headless backends, this is GLib-based. The Gtk2 backend creates a GtkWindow and that is how the user sees and interacts with the application. On the headless backend, there is no visible window. It can only be used for embedding via libxul.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
Chris has a [http://chrislord.net/files/fosdem-09-slides.odp presentation] that explains the headless branch a bit and [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten instructions on how to build it].&lt;br /&gt;
&lt;br /&gt;
--- &lt;br /&gt;
&lt;br /&gt;
There&#039;s an [https://bugzilla.mozilla.org/show_bug.cgi?id=446591 existing bug] that deals with headless UI.&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Can Android run a completely native app? ==&lt;br /&gt;
&lt;br /&gt;
According to  [http://sites.google.com/site/io/anatomy--physiology-of-an-android Anatomy and physiology] and [http://developer.android.com/guide/topics/fundamentals.html Android Fundamentals], each Android process has its own Java virtual machine (VM), so application code runs in isolation from the code of all other applications. &lt;br /&gt;
&lt;br /&gt;
Android processes (Java VMs) communicate with the Home App and various system services via the [http://en.wikipedia.org/wiki/OpenBinder Binder IPC] described using [http://developer.android.com/guide/developing/tools/aidl.html Android Interface Definition Language (AIDL)].&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;Home Application&#039;&#039; (Launcher) is the app that displays the Android desktop and allows the [file:///Volumes/android/mydroid/frameworks/base/core/java/android/app/LauncherActivity.java launching of other apps] by clicking on their icons. &lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;activity&#039;&#039; presents a visual user interface for one focused endeavor the user can undertake. For example, an activity might present a list of menu items users can choose from or it might display photographs along with their captions. A text messaging application might have one activity that shows a list of contacts to send messages to, a second activity to write the message to the chosen contact, and other activities to review old messages or change settings.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;task&#039;&#039; is a group of related activities. May include activities from other apps, running in other processes, e.g. map viewer. A task has an activity stack. &lt;br /&gt;
&lt;br /&gt;
Any given activity  &lt;br /&gt;
- Has a content view that is created using a layout resource.&lt;br /&gt;
- Can be floating or embedded inside another activity.&lt;br /&gt;
- Has a pause callback invoked when the user is leaving the activity.&lt;br /&gt;
- Is visible when it&#039;s at the top of the stack for the current task.&lt;br /&gt;
- Is paused when there&#039;s another activity on top of it but remains visible. It has lost focus but remains completely alive and attached to the window manager but can be killed in low memory conditions.&lt;br /&gt;
- Is stopped when it&#039;s completely obscured by another activity. The window is hidden and activity will be killed when memory is needed elsewhere. &lt;br /&gt;
- Has a finish callback that may be called when the activity is being evicted from memory.&lt;br /&gt;
- Generates a thumbnail of the activity via a callback that&#039;s called before pausing.&lt;br /&gt;
- Receives trackball and key events via callbacks.&lt;br /&gt;
&lt;br /&gt;
When an app icon is clicked, the Home app uses the package manager to retrive app info and package it into an [file:///Volumes/android/mydroid/frameworks/base/core/java/android/content/Intent.java intent], an asynchronous message with information necessary to start a given activity. The Home app then uses startActivity, a method of Context to launch the activity. [file:///Volumes/android/mydroid/frameworks/base/core/java/android/content/Context.java Context is an abstract class] whose implementation is provided by the Android system.&lt;br /&gt;
&lt;br /&gt;
The launch request is sent via the Binder IPC to the [file:///Volumes/android/mydroid/frameworks/base/services/java/com/android/server/am/ActivityManagerService.java Activity Manager Service] which uses the [file:///Volumes/android/mydroid/frameworks/base/core/java/android/os/Process.java Process] class to start an [file:///Volumes/android/mydroid/frameworks/base/core/java/android/app/ActivityThread.java Activity Thread] in a new instance of the Dalvik Java VM via the [file:///Volumes/android/mydroid//Volumes/android/mydroid/system/core/libcutils/zygote.c Zygote].&lt;br /&gt;
&lt;br /&gt;
The mechanism above assumes Java is used to implement activities. For example, the first non-option argument to Zygote should be a class name in the system class path. Also, [http://developer.android.com/guide/developing/tools/aidl.html aidl command-line tool] only generates Java code for Binder IPCs. &lt;br /&gt;
&lt;br /&gt;
While I&#039;m confident that I could write a native application that plugs into the Android event stream as well as the activity, window, etc. managers, doing so would require adding C++ code generation to the &#039;&#039;aidl tool&#039;&#039; and implementing the portion of the Android Java SDK that deals with the activity life cycle. &lt;br /&gt;
&lt;br /&gt;
Still, it will not be possible to launch a native app from the Home app due to the Java assumptions in the core launching mechanism, so a Java shim will be required. There may be a great deal of flexibility in running a completely native app since, for example, OpenGL ES is not required and the screen (surface) buffer can be written to directly. Another alternative is to let the Java shim handle act as an invisible &#039;&#039;activity&#039;&#039; that uses the NDK to pass events to native code running in a shared library. OpenGL ES will be required in the latter case to write to a pre-configured screen context.&lt;br /&gt;
&lt;br /&gt;
== Sample external application Makefile ==&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you can build your own native apps without being shoehorned into the Android SDK build structure. I got this by massaging the output of &#039;&#039;make showcommands&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SDK := /Volumes/android/mydroid&lt;br /&gt;
TOOLCHAIN := $(SDK)/prebuilt/darwin-x86/toolchain/arm-eabi-4.2.1&lt;br /&gt;
ABILIB := $(TOOLCHAIN)/lib/gcc/arm-eabi/4.2.1/&lt;br /&gt;
BIN := $(TOOLCHAIN)/bin&lt;br /&gt;
C++ := $(BIN)/arm-eabi-g++&lt;br /&gt;
CC := $(BIN)/arm-eabi-gcc&lt;br /&gt;
&lt;br /&gt;
INCLUDE := \&lt;br /&gt;
  -I$(SDK)/system/core/include \&lt;br /&gt;
  -I$(SDK)/hardware/libhardware/include \&lt;br /&gt;
  -I$(SDK)/hardware/libhardware_legacy/include \&lt;br /&gt;
  -I$(SDK)/hardware/ril/include \&lt;br /&gt;
  -I$(SDK)/dalvik/libnativehelper/include \&lt;br /&gt;
  -I$(SDK)/frameworks/base/include \&lt;br /&gt;
  -I$(SDK)/frameworks/base/opengl/include \&lt;br /&gt;
  -I$(SDK)/external/skia/include \&lt;br /&gt;
  -I$(SDK)/out/target/product/generic/obj/include \&lt;br /&gt;
  -I$(SDK)/bionic/libc/arch-arm/include \&lt;br /&gt;
  -I$(SDK)/bionic/libc/include \&lt;br /&gt;
  -I$(SDK)/bionic/libstdc++/include \&lt;br /&gt;
  -I$(SDK)/bionic/libc/kernel/common \&lt;br /&gt;
  -I$(SDK)/bionic/libc/kernel/arch-arm \&lt;br /&gt;
  -I$(SDK)/bionic/libm/include \&lt;br /&gt;
  -I$(SDK)/bionic/libm/include/arch/arm \&lt;br /&gt;
  -I$(SDK)/bionic/libthread_db/include \&lt;br /&gt;
  -I$(SDK)/frameworks/base/cmds/demo \&lt;br /&gt;
  -I$(SDK)/system/core/include/arch/linux-arm \&lt;br /&gt;
  -include $(SDK)/system/core/include/arch/linux-arm/AndroidConfig.h \&lt;br /&gt;
  $(NULL)&lt;br /&gt;
  &lt;br /&gt;
CFLAGS = \&lt;br /&gt;
  -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5TE__ -DANDROID \&lt;br /&gt;
  -DSK_RELEASE -DNDEBUG -UDEBUG \&lt;br /&gt;
  -mthumb -mthumb-interwork -msoft-float -march=armv5te -mtune=xscale \&lt;br /&gt;
  -fpic -fno-exceptions -ffunction-sections -funwind-tables -fstack-protector \&lt;br /&gt;
  -fno-short-enums -fmessage-length=0 -finline-functions -fno-inline-functions-called-once \&lt;br /&gt;
  -fgcse-after-reload -frerun-cse-after-loop -frename-registers -fvisibility-inlines-hidden \&lt;br /&gt;
  -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -fno-rtti \&lt;br /&gt;
  -W -Wall -Wno-multichar -Wno-unused -Werror=return-type -Wstrict-aliasing=2 \&lt;br /&gt;
  -Wnon-virtual-dtor -Werror=return-type \&lt;br /&gt;
  -MD -Os -g \&lt;br /&gt;
  $(NULL)&lt;br /&gt;
 &lt;br /&gt;
LIBDIR := $(SDK)/out/target/product/generic/obj/lib&lt;br /&gt;
&lt;br /&gt;
LIBS := -lui -llog -lutils -lc -lstdc++ -lm $(LIBDIR)/crtbegin_dynamic.o &lt;br /&gt;
  &lt;br /&gt;
LDFLAGS := \&lt;br /&gt;
  -nostdlib -Bdynamic -Wl,--no-undefined -Wl,-T,$(SDK)/build/core/armelf.x \&lt;br /&gt;
  -Wl,-dynamic-linker,$(SDK)/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc \&lt;br /&gt;
  -L$(LIBDIR) -Wl,-rpath-link=$(LIBDIR) \&lt;br /&gt;
  $(NULL)&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
all: demo&lt;br /&gt;
&lt;br /&gt;
demo: surfaceflinger.o demo.o&lt;br /&gt;
	$(C++) $(LDFLAGS) -o demo $(LIBS) surfaceflinger.o demo.o \&lt;br /&gt;
		$(ABILIB)/interwork/libgcc.a $(LIBDIR)/crtend_android.o&lt;br /&gt;
&lt;br /&gt;
surfaceflinger.o: &lt;br /&gt;
	$(C++) $(INCLUDE) -c $(CFLAGS) surfaceflinger.cpp&lt;br /&gt;
&lt;br /&gt;
demo.o:&lt;br /&gt;
	$(CC) $(INCLUDE) -c $(CFLAGS) demo.c&lt;br /&gt;
&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f demo *.o	&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction to the Android Window System ==&lt;br /&gt;
&lt;br /&gt;
[http://people.debian.org.tw/%7Eolv/surfaceflinger/surfaceflinger.pdf Slides] and [http://people.debian.org.tw/%7Eolv/surfaceflinger/demo.tar.gz demo code].&lt;br /&gt;
&lt;br /&gt;
== Building and running the OpenGL ES NDK example == &lt;br /&gt;
&lt;br /&gt;
Here&#039;s how to build and run the san-angeles application from NDK 1.6. This program demonstrates how to use a GLSurfaceView from Java along with native OpenGL calls to perform frame rendering.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cd /Volumes/android/mydroid/&lt;br /&gt;
. build/envsetup.sh &lt;br /&gt;
including vendor/aosp/vendorsetup.sh&lt;br /&gt;
lunch sdk-eng&lt;br /&gt;
&lt;br /&gt;
============================================&lt;br /&gt;
PLATFORM_VERSION_CODENAME=REL&lt;br /&gt;
PLATFORM_VERSION=1.6&lt;br /&gt;
TARGET_PRODUCT=sdk&lt;br /&gt;
TARGET_BUILD_VARIANT=eng&lt;br /&gt;
TARGET_SIMULATOR=false&lt;br /&gt;
TARGET_BUILD_TYPE=release&lt;br /&gt;
TARGET_ARCH=arm&lt;br /&gt;
HOST_ARCH=x86&lt;br /&gt;
HOST_OS=darwin&lt;br /&gt;
HOST_BUILD_TYPE=release&lt;br /&gt;
BUILD_ID=Donut&lt;br /&gt;
============================================&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First, we need to build the shared library of native code &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/work/android/android-ndk-1.6_r1/&lt;br /&gt;
build/host-setup.sh&lt;br /&gt;
make APP=san-angeles&lt;br /&gt;
&lt;br /&gt;
Android NDK: Building for application &#039;san-angeles&#039;    &lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/importgl.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/demo.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/app-android.c&lt;br /&gt;
SharedLibrary  : libsanangeles.so&lt;br /&gt;
Install        : libsanangeles.so =&amp;gt; apps/san-angeles/project/libs/armeabi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we need to make sure we can build the Java portion of the project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android update project --path apps/san-angeles/project&lt;br /&gt;
&lt;br /&gt;
Updated local.properties&lt;br /&gt;
File build.xml is too old and needs to be updated.&lt;br /&gt;
Added file apps/san-angeles/project/build.xml&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, let&#039;s build the debug release of project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd apps/san-angeles/project/&lt;br /&gt;
ant debug&lt;br /&gt;
&lt;br /&gt;
Buildfile: build.xml&lt;br /&gt;
    [setup] Project Target: Android 1.6&lt;br /&gt;
    [setup] API level: 4&lt;br /&gt;
&lt;br /&gt;
dirs:&lt;br /&gt;
     [echo] Creating output directories if needed...&lt;br /&gt;
&lt;br /&gt;
resource-src:&lt;br /&gt;
     [echo] Generating R.java / Manifest.java from the resources...&lt;br /&gt;
&lt;br /&gt;
aidl:&lt;br /&gt;
     [echo] Compiling aidl files into Java classes...&lt;br /&gt;
&lt;br /&gt;
compile:&lt;br /&gt;
    [javac] Compiling 1 source file to /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes&lt;br /&gt;
&lt;br /&gt;
dex:&lt;br /&gt;
     [echo] Converting compiled files and external libraries into bin/classes.dex...&lt;br /&gt;
&lt;br /&gt;
package-resources:&lt;br /&gt;
     [echo] Packaging resources&lt;br /&gt;
 [aaptexec] Creating full resource package...&lt;br /&gt;
&lt;br /&gt;
debug-sign:&lt;br /&gt;
&lt;br /&gt;
package:&lt;br /&gt;
[apkbuilder] Creating .DemoActivity-debug-unaligned.apk and signing it with a debug key...&lt;br /&gt;
[apkbuilder] Using keystore: /Users/joelr/.android/debug.keystore&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes.dex =&amp;gt; classes.dex&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/libs/armeabi/libsanangeles.so =&amp;gt; lib/armeabi/libsanangeles.so&lt;br /&gt;
&lt;br /&gt;
debug:&lt;br /&gt;
     [echo] Running zip align on final apk...&lt;br /&gt;
     [echo] Debug Package: bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
BUILD SUCCESSFUL&lt;br /&gt;
Total time: 1 second&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, let&#039;s install the app on the device&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adb install -r bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
1107 KB/s (13707 bytes in 0.012s)&lt;br /&gt;
	pkg: /data/local/tmp/.DemoActivity-debug.apk&lt;br /&gt;
Success&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run the app click on the &amp;quot;tab&amp;quot; at the bottom of the Android emulator screen and then on the DemoActivity icon in the list of applications. Enjoy!&lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For [http://code.google.com/p/glesquake/ Quake], GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. lunch sdk-eng &amp;amp;&amp;amp; make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=176114</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=176114"/>
		<updated>2009-10-16T15:37:24Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Android Notes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 12, 2009 ==&lt;br /&gt;
&lt;br /&gt;
Via Chris Lord...&lt;br /&gt;
&lt;br /&gt;
The [http://hg.mozilla.org/incubator/offscreen headless branch of Mozilla that we work on] renders to system memory and it is up to the embedder to get this to a texture however they like. We have our own embedding library that uses this with Clutter&lt;br /&gt;
[http://git.clutter-project.org/?r=clutter-mozembed clutter-mozembed] and we just upload each changed region to the texture.&lt;br /&gt;
&lt;br /&gt;
A possible speed-up is to use a shared memory pixmap and texture-from-pixmap (or whatever the platform&#039;s equivalent is), which&lt;br /&gt;
would remove the need to copy from system to video memory.&lt;br /&gt;
&lt;br /&gt;
I wrote a (now out-dated, but still relevant) [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten guide on building the Moblin browser components] on my blog. There&#039;s also a [http://chrislord.net/files/moz-headless-screenshot.c short demo application I wrote] that just uses mozilla-headless alone to take a screenshot of a web-page. &lt;br /&gt;
&lt;br /&gt;
Unfortunately, there is no documentation beyond the standard Mozilla documentation and the source-code (and the above-mentioned links).&lt;br /&gt;
&lt;br /&gt;
I think the easiest way to port Firefox to android would be to write an android-backend (which could well be based on our headless backend) - I didn&#039;t think that the Android native development kit was fully featured enough to allow something like this though?&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
You can&#039;t run Firefox with the headless backend as it is, it&#039;s designed to be embedded and for libxul to be used. The headless backend is also heavily dependent on GLib (for the main loop, signals and idle handlers).&lt;br /&gt;
&lt;br /&gt;
If you wanted to run Firefox, you&#039;d have to write a new backend, or modify an existing one, to provide the application framework. In the gtk2 and headless backends, this is GLib-based. The Gtk2 backend creates a GtkWindow and that is how the user sees and interacts with the application. On the headless backend, there is no visible window. It can only be used for embedding via libxul.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
Chris has a [http://chrislord.net/files/fosdem-09-slides.odp presentation] that explains the headless branch a bit and [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten instructions on how to build it].&lt;br /&gt;
&lt;br /&gt;
--- &lt;br /&gt;
&lt;br /&gt;
There&#039;s an [https://bugzilla.mozilla.org/show_bug.cgi?id=446591 existing bug] that deals with headless UI.&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Sample external application Makefile ==&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you can build your own native apps without being shoehorned into the Android SDK build structure. I got this by massaging the output of &#039;&#039;make showcommands&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SDK := /Volumes/android/mydroid&lt;br /&gt;
TOOLCHAIN := $(SDK)/prebuilt/darwin-x86/toolchain/arm-eabi-4.2.1&lt;br /&gt;
ABILIB := $(TOOLCHAIN)/lib/gcc/arm-eabi/4.2.1/&lt;br /&gt;
BIN := $(TOOLCHAIN)/bin&lt;br /&gt;
C++ := $(BIN)/arm-eabi-g++&lt;br /&gt;
CC := $(BIN)/arm-eabi-gcc&lt;br /&gt;
&lt;br /&gt;
INCLUDE := \&lt;br /&gt;
  -I$(SDK)/system/core/include \&lt;br /&gt;
  -I$(SDK)/hardware/libhardware/include \&lt;br /&gt;
  -I$(SDK)/hardware/libhardware_legacy/include \&lt;br /&gt;
  -I$(SDK)/hardware/ril/include \&lt;br /&gt;
  -I$(SDK)/dalvik/libnativehelper/include \&lt;br /&gt;
  -I$(SDK)/frameworks/base/include \&lt;br /&gt;
  -I$(SDK)/frameworks/base/opengl/include \&lt;br /&gt;
  -I$(SDK)/external/skia/include \&lt;br /&gt;
  -I$(SDK)/out/target/product/generic/obj/include \&lt;br /&gt;
  -I$(SDK)/bionic/libc/arch-arm/include \&lt;br /&gt;
  -I$(SDK)/bionic/libc/include \&lt;br /&gt;
  -I$(SDK)/bionic/libstdc++/include \&lt;br /&gt;
  -I$(SDK)/bionic/libc/kernel/common \&lt;br /&gt;
  -I$(SDK)/bionic/libc/kernel/arch-arm \&lt;br /&gt;
  -I$(SDK)/bionic/libm/include \&lt;br /&gt;
  -I$(SDK)/bionic/libm/include/arch/arm \&lt;br /&gt;
  -I$(SDK)/bionic/libthread_db/include \&lt;br /&gt;
  -I$(SDK)/frameworks/base/cmds/demo \&lt;br /&gt;
  -I$(SDK)/system/core/include/arch/linux-arm \&lt;br /&gt;
  -include $(SDK)/system/core/include/arch/linux-arm/AndroidConfig.h \&lt;br /&gt;
  $(NULL)&lt;br /&gt;
  &lt;br /&gt;
CFLAGS = \&lt;br /&gt;
  -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5TE__ -DANDROID \&lt;br /&gt;
  -DSK_RELEASE -DNDEBUG -UDEBUG \&lt;br /&gt;
  -mthumb -mthumb-interwork -msoft-float -march=armv5te -mtune=xscale \&lt;br /&gt;
  -fpic -fno-exceptions -ffunction-sections -funwind-tables -fstack-protector \&lt;br /&gt;
  -fno-short-enums -fmessage-length=0 -finline-functions -fno-inline-functions-called-once \&lt;br /&gt;
  -fgcse-after-reload -frerun-cse-after-loop -frename-registers -fvisibility-inlines-hidden \&lt;br /&gt;
  -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -fno-rtti \&lt;br /&gt;
  -W -Wall -Wno-multichar -Wno-unused -Werror=return-type -Wstrict-aliasing=2 \&lt;br /&gt;
  -Wnon-virtual-dtor -Werror=return-type \&lt;br /&gt;
  -MD -Os -g \&lt;br /&gt;
  $(NULL)&lt;br /&gt;
 &lt;br /&gt;
LIBDIR := $(SDK)/out/target/product/generic/obj/lib&lt;br /&gt;
&lt;br /&gt;
LIBS := -lui -llog -lutils -lc -lstdc++ -lm $(LIBDIR)/crtbegin_dynamic.o &lt;br /&gt;
  &lt;br /&gt;
LDFLAGS := \&lt;br /&gt;
  -nostdlib -Bdynamic -Wl,--no-undefined -Wl,-T,$(SDK)/build/core/armelf.x \&lt;br /&gt;
  -Wl,-dynamic-linker,$(SDK)/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc \&lt;br /&gt;
  -L$(LIBDIR) -Wl,-rpath-link=$(LIBDIR) \&lt;br /&gt;
  $(NULL)&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
all: demo&lt;br /&gt;
&lt;br /&gt;
demo: surfaceflinger.o demo.o&lt;br /&gt;
	$(C++) $(LDFLAGS) -o demo $(LIBS) surfaceflinger.o demo.o \&lt;br /&gt;
		$(ABILIB)/interwork/libgcc.a $(LIBDIR)/crtend_android.o&lt;br /&gt;
&lt;br /&gt;
surfaceflinger.o: &lt;br /&gt;
	$(C++) $(INCLUDE) -c $(CFLAGS) surfaceflinger.cpp&lt;br /&gt;
&lt;br /&gt;
demo.o:&lt;br /&gt;
	$(CC) $(INCLUDE) -c $(CFLAGS) demo.c&lt;br /&gt;
&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f demo *.o	&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction to the Android Window System ==&lt;br /&gt;
&lt;br /&gt;
[http://people.debian.org.tw/%7Eolv/surfaceflinger/surfaceflinger.pdf Slides] and [http://people.debian.org.tw/%7Eolv/surfaceflinger/demo.tar.gz demo code].&lt;br /&gt;
&lt;br /&gt;
== Building and running the OpenGL ES NDK example == &lt;br /&gt;
&lt;br /&gt;
Here&#039;s how to build and run the san-angeles application from NDK 1.6. This program demonstrates how to use a GLSurfaceView from Java along with native OpenGL calls to perform frame rendering.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cd /Volumes/android/mydroid/&lt;br /&gt;
. build/envsetup.sh &lt;br /&gt;
including vendor/aosp/vendorsetup.sh&lt;br /&gt;
lunch sdk-eng&lt;br /&gt;
&lt;br /&gt;
============================================&lt;br /&gt;
PLATFORM_VERSION_CODENAME=REL&lt;br /&gt;
PLATFORM_VERSION=1.6&lt;br /&gt;
TARGET_PRODUCT=sdk&lt;br /&gt;
TARGET_BUILD_VARIANT=eng&lt;br /&gt;
TARGET_SIMULATOR=false&lt;br /&gt;
TARGET_BUILD_TYPE=release&lt;br /&gt;
TARGET_ARCH=arm&lt;br /&gt;
HOST_ARCH=x86&lt;br /&gt;
HOST_OS=darwin&lt;br /&gt;
HOST_BUILD_TYPE=release&lt;br /&gt;
BUILD_ID=Donut&lt;br /&gt;
============================================&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First, we need to build the shared library of native code &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/work/android/android-ndk-1.6_r1/&lt;br /&gt;
build/host-setup.sh&lt;br /&gt;
make APP=san-angeles&lt;br /&gt;
&lt;br /&gt;
Android NDK: Building for application &#039;san-angeles&#039;    &lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/importgl.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/demo.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/app-android.c&lt;br /&gt;
SharedLibrary  : libsanangeles.so&lt;br /&gt;
Install        : libsanangeles.so =&amp;gt; apps/san-angeles/project/libs/armeabi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we need to make sure we can build the Java portion of the project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android update project --path apps/san-angeles/project&lt;br /&gt;
&lt;br /&gt;
Updated local.properties&lt;br /&gt;
File build.xml is too old and needs to be updated.&lt;br /&gt;
Added file apps/san-angeles/project/build.xml&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, let&#039;s build the debug release of project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd apps/san-angeles/project/&lt;br /&gt;
ant debug&lt;br /&gt;
&lt;br /&gt;
Buildfile: build.xml&lt;br /&gt;
    [setup] Project Target: Android 1.6&lt;br /&gt;
    [setup] API level: 4&lt;br /&gt;
&lt;br /&gt;
dirs:&lt;br /&gt;
     [echo] Creating output directories if needed...&lt;br /&gt;
&lt;br /&gt;
resource-src:&lt;br /&gt;
     [echo] Generating R.java / Manifest.java from the resources...&lt;br /&gt;
&lt;br /&gt;
aidl:&lt;br /&gt;
     [echo] Compiling aidl files into Java classes...&lt;br /&gt;
&lt;br /&gt;
compile:&lt;br /&gt;
    [javac] Compiling 1 source file to /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes&lt;br /&gt;
&lt;br /&gt;
dex:&lt;br /&gt;
     [echo] Converting compiled files and external libraries into bin/classes.dex...&lt;br /&gt;
&lt;br /&gt;
package-resources:&lt;br /&gt;
     [echo] Packaging resources&lt;br /&gt;
 [aaptexec] Creating full resource package...&lt;br /&gt;
&lt;br /&gt;
debug-sign:&lt;br /&gt;
&lt;br /&gt;
package:&lt;br /&gt;
[apkbuilder] Creating .DemoActivity-debug-unaligned.apk and signing it with a debug key...&lt;br /&gt;
[apkbuilder] Using keystore: /Users/joelr/.android/debug.keystore&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes.dex =&amp;gt; classes.dex&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/libs/armeabi/libsanangeles.so =&amp;gt; lib/armeabi/libsanangeles.so&lt;br /&gt;
&lt;br /&gt;
debug:&lt;br /&gt;
     [echo] Running zip align on final apk...&lt;br /&gt;
     [echo] Debug Package: bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
BUILD SUCCESSFUL&lt;br /&gt;
Total time: 1 second&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, let&#039;s install the app on the device&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adb install -r bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
1107 KB/s (13707 bytes in 0.012s)&lt;br /&gt;
	pkg: /data/local/tmp/.DemoActivity-debug.apk&lt;br /&gt;
Success&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run the app click on the &amp;quot;tab&amp;quot; at the bottom of the Android emulator screen and then on the DemoActivity icon in the list of applications. Enjoy!&lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For [http://code.google.com/p/glesquake/ Quake], GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. lunch sdk-eng &amp;amp;&amp;amp; make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=175534</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=175534"/>
		<updated>2009-10-14T15:30:07Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Android Notes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 12, 2009 ==&lt;br /&gt;
&lt;br /&gt;
Via Chris Lord...&lt;br /&gt;
&lt;br /&gt;
The [http://hg.mozilla.org/incubator/offscreen headless branch of Mozilla that we work on] renders to system memory and it is up to the embedder to get this to a texture however they like. We have our own embedding library that uses this with Clutter&lt;br /&gt;
[http://git.clutter-project.org/?r=clutter-mozembed clutter-mozembed] and we just upload each changed region to the texture.&lt;br /&gt;
&lt;br /&gt;
A possible speed-up is to use a shared memory pixmap and texture-from-pixmap (or whatever the platform&#039;s equivalent is), which&lt;br /&gt;
would remove the need to copy from system to video memory.&lt;br /&gt;
&lt;br /&gt;
I wrote a (now out-dated, but still relevant) [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten guide on building the Moblin browser components] on my blog. There&#039;s also a [http://chrislord.net/files/moz-headless-screenshot.c short demo application I wrote] that just uses mozilla-headless alone to take a screenshot of a web-page. &lt;br /&gt;
&lt;br /&gt;
Unfortunately, there is no documentation beyond the standard Mozilla documentation and the source-code (and the above-mentioned links).&lt;br /&gt;
&lt;br /&gt;
I think the easiest way to port Firefox to android would be to write an android-backend (which could well be based on our headless backend) - I didn&#039;t think that the Android native development kit was fully featured enough to allow something like this though?&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
You can&#039;t run Firefox with the headless backend as it is, it&#039;s designed to be embedded and for libxul to be used. The headless backend is also heavily dependent on GLib (for the main loop, signals and idle handlers).&lt;br /&gt;
&lt;br /&gt;
If you wanted to run Firefox, you&#039;d have to write a new backend, or modify an existing one, to provide the application framework. In the gtk2 and headless backends, this is GLib-based. The Gtk2 backend creates a GtkWindow and that is how the user sees and interacts with the application. On the headless backend, there is no visible window. It can only be used for embedding via libxul.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
Chris has a [http://chrislord.net/files/fosdem-09-slides.odp presentation] that explains the headless branch a bit and [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten instructions on how to build it].&lt;br /&gt;
&lt;br /&gt;
--- &lt;br /&gt;
&lt;br /&gt;
There&#039;s an [https://bugzilla.mozilla.org/show_bug.cgi?id=446591 existing bug] that deals with headless UI.&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the Android Window System ==&lt;br /&gt;
&lt;br /&gt;
[http://people.debian.org.tw/%7Eolv/surfaceflinger/surfaceflinger.pdf Slides] and [http://people.debian.org.tw/%7Eolv/surfaceflinger/demo.tar.gz demo code].&lt;br /&gt;
&lt;br /&gt;
== Building and running the OpenGL ES NDK example == &lt;br /&gt;
&lt;br /&gt;
Here&#039;s how to build and run the san-angeles application from NDK 1.6. This program demonstrates how to use a GLSurfaceView from Java along with native OpenGL calls to perform frame rendering.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cd /Volumes/android/mydroid/&lt;br /&gt;
. build/envsetup.sh &lt;br /&gt;
including vendor/aosp/vendorsetup.sh&lt;br /&gt;
lunch sdk-eng&lt;br /&gt;
&lt;br /&gt;
============================================&lt;br /&gt;
PLATFORM_VERSION_CODENAME=REL&lt;br /&gt;
PLATFORM_VERSION=1.6&lt;br /&gt;
TARGET_PRODUCT=sdk&lt;br /&gt;
TARGET_BUILD_VARIANT=eng&lt;br /&gt;
TARGET_SIMULATOR=false&lt;br /&gt;
TARGET_BUILD_TYPE=release&lt;br /&gt;
TARGET_ARCH=arm&lt;br /&gt;
HOST_ARCH=x86&lt;br /&gt;
HOST_OS=darwin&lt;br /&gt;
HOST_BUILD_TYPE=release&lt;br /&gt;
BUILD_ID=Donut&lt;br /&gt;
============================================&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First, we need to build the shared library of native code &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/work/android/android-ndk-1.6_r1/&lt;br /&gt;
build/host-setup.sh&lt;br /&gt;
make APP=san-angeles&lt;br /&gt;
&lt;br /&gt;
Android NDK: Building for application &#039;san-angeles&#039;    &lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/importgl.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/demo.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/app-android.c&lt;br /&gt;
SharedLibrary  : libsanangeles.so&lt;br /&gt;
Install        : libsanangeles.so =&amp;gt; apps/san-angeles/project/libs/armeabi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we need to make sure we can build the Java portion of the project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android update project --path apps/san-angeles/project&lt;br /&gt;
&lt;br /&gt;
Updated local.properties&lt;br /&gt;
File build.xml is too old and needs to be updated.&lt;br /&gt;
Added file apps/san-angeles/project/build.xml&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, let&#039;s build the debug release of project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd apps/san-angeles/project/&lt;br /&gt;
ant debug&lt;br /&gt;
&lt;br /&gt;
Buildfile: build.xml&lt;br /&gt;
    [setup] Project Target: Android 1.6&lt;br /&gt;
    [setup] API level: 4&lt;br /&gt;
&lt;br /&gt;
dirs:&lt;br /&gt;
     [echo] Creating output directories if needed...&lt;br /&gt;
&lt;br /&gt;
resource-src:&lt;br /&gt;
     [echo] Generating R.java / Manifest.java from the resources...&lt;br /&gt;
&lt;br /&gt;
aidl:&lt;br /&gt;
     [echo] Compiling aidl files into Java classes...&lt;br /&gt;
&lt;br /&gt;
compile:&lt;br /&gt;
    [javac] Compiling 1 source file to /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes&lt;br /&gt;
&lt;br /&gt;
dex:&lt;br /&gt;
     [echo] Converting compiled files and external libraries into bin/classes.dex...&lt;br /&gt;
&lt;br /&gt;
package-resources:&lt;br /&gt;
     [echo] Packaging resources&lt;br /&gt;
 [aaptexec] Creating full resource package...&lt;br /&gt;
&lt;br /&gt;
debug-sign:&lt;br /&gt;
&lt;br /&gt;
package:&lt;br /&gt;
[apkbuilder] Creating .DemoActivity-debug-unaligned.apk and signing it with a debug key...&lt;br /&gt;
[apkbuilder] Using keystore: /Users/joelr/.android/debug.keystore&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes.dex =&amp;gt; classes.dex&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/libs/armeabi/libsanangeles.so =&amp;gt; lib/armeabi/libsanangeles.so&lt;br /&gt;
&lt;br /&gt;
debug:&lt;br /&gt;
     [echo] Running zip align on final apk...&lt;br /&gt;
     [echo] Debug Package: bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
BUILD SUCCESSFUL&lt;br /&gt;
Total time: 1 second&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, let&#039;s install the app on the device&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adb install -r bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
1107 KB/s (13707 bytes in 0.012s)&lt;br /&gt;
	pkg: /data/local/tmp/.DemoActivity-debug.apk&lt;br /&gt;
Success&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run the app click on the &amp;quot;tab&amp;quot; at the bottom of the Android emulator screen and then on the DemoActivity icon in the list of applications. Enjoy!&lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For [http://code.google.com/p/glesquake/ Quake], GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. lunch sdk-eng &amp;amp;&amp;amp; make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=175416</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=175416"/>
		<updated>2009-10-13T21:48:43Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Building and running the OpenGL ES NDK example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 12, 2009 ==&lt;br /&gt;
&lt;br /&gt;
Via Chris Lord...&lt;br /&gt;
&lt;br /&gt;
The [http://hg.mozilla.org/incubator/offscreen headless branch of Mozilla that we work on] renders to system memory and it is up to the embedder to get this to a texture however they like. We have our own embedding library that uses this with Clutter&lt;br /&gt;
[http://git.clutter-project.org/?r=clutter-mozembed clutter-mozembed] and we just upload each changed region to the texture.&lt;br /&gt;
&lt;br /&gt;
A possible speed-up is to use a shared memory pixmap and texture-from-pixmap (or whatever the platform&#039;s equivalent is), which&lt;br /&gt;
would remove the need to copy from system to video memory.&lt;br /&gt;
&lt;br /&gt;
I wrote a (now out-dated, but still relevant) [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten guide on building the Moblin browser components] on my blog. There&#039;s also a [http://chrislord.net/files/moz-headless-screenshot.c short demo application I wrote] that just uses mozilla-headless alone to take a screenshot of a web-page. &lt;br /&gt;
&lt;br /&gt;
Unfortunately, there is no documentation beyond the standard Mozilla documentation and the source-code (and the above-mentioned links).&lt;br /&gt;
&lt;br /&gt;
I think the easiest way to port Firefox to android would be to write an android-backend (which could well be based on our headless backend) - I didn&#039;t think that the Android native development kit was fully featured enough to allow something like this though?&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
You can&#039;t run Firefox with the headless backend as it is, it&#039;s designed to be embedded and for libxul to be used. The headless backend is also heavily dependent on GLib (for the main loop, signals and idle handlers).&lt;br /&gt;
&lt;br /&gt;
If you wanted to run Firefox, you&#039;d have to write a new backend, or modify an existing one, to provide the application framework. In the gtk2 and headless backends, this is GLib-based. The Gtk2 backend creates a GtkWindow and that is how the user sees and interacts with the application. On the headless backend, there is no visible window. It can only be used for embedding via libxul.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
Chris has a [http://chrislord.net/files/fosdem-09-slides.odp presentation] that explains the headless branch a bit and [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten instructions on how to build it].&lt;br /&gt;
&lt;br /&gt;
--- &lt;br /&gt;
&lt;br /&gt;
There&#039;s an [https://bugzilla.mozilla.org/show_bug.cgi?id=446591 existing bug] that deals with headless UI.&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building and running the OpenGL ES NDK example == &lt;br /&gt;
&lt;br /&gt;
Here&#039;s how to build and run the san-angeles application from NDK 1.6. This program demonstrates how to use a GLSurfaceView from Java along with native OpenGL calls to perform frame rendering.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cd /Volumes/android/mydroid/&lt;br /&gt;
. build/envsetup.sh &lt;br /&gt;
including vendor/aosp/vendorsetup.sh&lt;br /&gt;
lunch sdk-eng&lt;br /&gt;
&lt;br /&gt;
============================================&lt;br /&gt;
PLATFORM_VERSION_CODENAME=REL&lt;br /&gt;
PLATFORM_VERSION=1.6&lt;br /&gt;
TARGET_PRODUCT=sdk&lt;br /&gt;
TARGET_BUILD_VARIANT=eng&lt;br /&gt;
TARGET_SIMULATOR=false&lt;br /&gt;
TARGET_BUILD_TYPE=release&lt;br /&gt;
TARGET_ARCH=arm&lt;br /&gt;
HOST_ARCH=x86&lt;br /&gt;
HOST_OS=darwin&lt;br /&gt;
HOST_BUILD_TYPE=release&lt;br /&gt;
BUILD_ID=Donut&lt;br /&gt;
============================================&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First, we need to build the shared library of native code &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/work/android/android-ndk-1.6_r1/&lt;br /&gt;
build/host-setup.sh&lt;br /&gt;
make APP=san-angeles&lt;br /&gt;
&lt;br /&gt;
Android NDK: Building for application &#039;san-angeles&#039;    &lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/importgl.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/demo.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/app-android.c&lt;br /&gt;
SharedLibrary  : libsanangeles.so&lt;br /&gt;
Install        : libsanangeles.so =&amp;gt; apps/san-angeles/project/libs/armeabi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we need to make sure we can build the Java portion of the project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android update project --path apps/san-angeles/project&lt;br /&gt;
&lt;br /&gt;
Updated local.properties&lt;br /&gt;
File build.xml is too old and needs to be updated.&lt;br /&gt;
Added file apps/san-angeles/project/build.xml&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, let&#039;s build the debug release of project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd apps/san-angeles/project/&lt;br /&gt;
ant debug&lt;br /&gt;
&lt;br /&gt;
Buildfile: build.xml&lt;br /&gt;
    [setup] Project Target: Android 1.6&lt;br /&gt;
    [setup] API level: 4&lt;br /&gt;
&lt;br /&gt;
dirs:&lt;br /&gt;
     [echo] Creating output directories if needed...&lt;br /&gt;
&lt;br /&gt;
resource-src:&lt;br /&gt;
     [echo] Generating R.java / Manifest.java from the resources...&lt;br /&gt;
&lt;br /&gt;
aidl:&lt;br /&gt;
     [echo] Compiling aidl files into Java classes...&lt;br /&gt;
&lt;br /&gt;
compile:&lt;br /&gt;
    [javac] Compiling 1 source file to /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes&lt;br /&gt;
&lt;br /&gt;
dex:&lt;br /&gt;
     [echo] Converting compiled files and external libraries into bin/classes.dex...&lt;br /&gt;
&lt;br /&gt;
package-resources:&lt;br /&gt;
     [echo] Packaging resources&lt;br /&gt;
 [aaptexec] Creating full resource package...&lt;br /&gt;
&lt;br /&gt;
debug-sign:&lt;br /&gt;
&lt;br /&gt;
package:&lt;br /&gt;
[apkbuilder] Creating .DemoActivity-debug-unaligned.apk and signing it with a debug key...&lt;br /&gt;
[apkbuilder] Using keystore: /Users/joelr/.android/debug.keystore&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes.dex =&amp;gt; classes.dex&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/libs/armeabi/libsanangeles.so =&amp;gt; lib/armeabi/libsanangeles.so&lt;br /&gt;
&lt;br /&gt;
debug:&lt;br /&gt;
     [echo] Running zip align on final apk...&lt;br /&gt;
     [echo] Debug Package: bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
BUILD SUCCESSFUL&lt;br /&gt;
Total time: 1 second&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, let&#039;s install the app on the device&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adb install -r bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
1107 KB/s (13707 bytes in 0.012s)&lt;br /&gt;
	pkg: /data/local/tmp/.DemoActivity-debug.apk&lt;br /&gt;
Success&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run the app click on the &amp;quot;tab&amp;quot; at the bottom of the Android emulator screen and then on the DemoActivity icon in the list of applications. Enjoy!&lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For [http://code.google.com/p/glesquake/ Quake], GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. lunch sdk-eng &amp;amp;&amp;amp; make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174927</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174927"/>
		<updated>2009-10-12T16:43:29Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* October 12, 2009 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 12, 2009 ==&lt;br /&gt;
&lt;br /&gt;
Via Chris Lord...&lt;br /&gt;
&lt;br /&gt;
The [http://hg.mozilla.org/incubator/offscreen headless branch of Mozilla that we work on] renders to system memory and it is up to the embedder to get this to a texture however they like. We have our own embedding library that uses this with Clutter&lt;br /&gt;
[http://git.clutter-project.org/?r=clutter-mozembed clutter-mozembed] and we just upload each changed region to the texture.&lt;br /&gt;
&lt;br /&gt;
A possible speed-up is to use a shared memory pixmap and texture-from-pixmap (or whatever the platform&#039;s equivalent is), which&lt;br /&gt;
would remove the need to copy from system to video memory.&lt;br /&gt;
&lt;br /&gt;
I wrote a (now out-dated, but still relevant) [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten guide on building the Moblin browser components] on my blog. There&#039;s also a [http://chrislord.net/files/moz-headless-screenshot.c short demo application I wrote] that just uses mozilla-headless alone to take a screenshot of a web-page. &lt;br /&gt;
&lt;br /&gt;
Unfortunately, there is no documentation beyond the standard Mozilla documentation and the source-code (and the above-mentioned links).&lt;br /&gt;
&lt;br /&gt;
I think the easiest way to port Firefox to android would be to write an android-backend (which could well be based on our headless backend) - I didn&#039;t think that the Android native development kit was fully featured enough to allow something like this though?&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
You can&#039;t run Firefox with the headless backend as it is, it&#039;s designed to be embedded and for libxul to be used. The headless backend is also heavily dependent on GLib (for the main loop, signals and idle handlers).&lt;br /&gt;
&lt;br /&gt;
If you wanted to run Firefox, you&#039;d have to write a new backend, or modify an existing one, to provide the application framework. In the gtk2 and headless backends, this is GLib-based. The Gtk2 backend creates a GtkWindow and that is how the user sees and interacts with the application. On the headless backend, there is no visible window. It can only be used for embedding via libxul.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
Chris has a [http://chrislord.net/files/fosdem-09-slides.odp presentation] that explains the headless branch a bit and [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten instructions on how to build it].&lt;br /&gt;
&lt;br /&gt;
--- &lt;br /&gt;
&lt;br /&gt;
There&#039;s an [https://bugzilla.mozilla.org/show_bug.cgi?id=446591 existing bug] that deals with headless UI.&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building and running the OpenGL ES NDK example == &lt;br /&gt;
&lt;br /&gt;
Here&#039;s how to build and run the san-angeles application from NDK 1.6. This program demonstrates how to use a GLSurfaceView from Java along with native OpenGL calls to perform frame rendering.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cd /Volumes/android/mydroid/&lt;br /&gt;
. build/envsetup.sh &lt;br /&gt;
including vendor/aosp/vendorsetup.sh&lt;br /&gt;
lunch sdk-eng&lt;br /&gt;
&lt;br /&gt;
============================================&lt;br /&gt;
PLATFORM_VERSION_CODENAME=REL&lt;br /&gt;
PLATFORM_VERSION=1.6&lt;br /&gt;
TARGET_PRODUCT=sdk&lt;br /&gt;
TARGET_BUILD_VARIANT=eng&lt;br /&gt;
TARGET_SIMULATOR=false&lt;br /&gt;
TARGET_BUILD_TYPE=release&lt;br /&gt;
TARGET_ARCH=arm&lt;br /&gt;
HOST_ARCH=x86&lt;br /&gt;
HOST_OS=darwin&lt;br /&gt;
HOST_BUILD_TYPE=release&lt;br /&gt;
BUILD_ID=Donut&lt;br /&gt;
============================================&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First, we need to build the shared library of native code &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/work/android/android-ndk-1.6_r1/&lt;br /&gt;
build/host-setup.sh&lt;br /&gt;
make APP=san-angeles&lt;br /&gt;
&lt;br /&gt;
Android NDK: Building for application &#039;san-angeles&#039;    &lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/importgl.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/demo.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/app-android.c&lt;br /&gt;
SharedLibrary  : libsanangeles.so&lt;br /&gt;
Install        : libsanangeles.so =&amp;gt; apps/san-angeles/project/libs/armeabi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we need to make sure we can build the Java portion of the project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android update project --path apps/san-angeles/project&lt;br /&gt;
&lt;br /&gt;
Updated local.properties&lt;br /&gt;
File build.xml is too old and needs to be updated.&lt;br /&gt;
Added file apps/san-angeles/project/build.xml&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, lets build the debug release of project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd apps/san-angeles/project/&lt;br /&gt;
ant debug&lt;br /&gt;
&lt;br /&gt;
Buildfile: build.xml&lt;br /&gt;
    [setup] Project Target: Android 1.6&lt;br /&gt;
    [setup] API level: 4&lt;br /&gt;
&lt;br /&gt;
dirs:&lt;br /&gt;
     [echo] Creating output directories if needed...&lt;br /&gt;
&lt;br /&gt;
resource-src:&lt;br /&gt;
     [echo] Generating R.java / Manifest.java from the resources...&lt;br /&gt;
&lt;br /&gt;
aidl:&lt;br /&gt;
     [echo] Compiling aidl files into Java classes...&lt;br /&gt;
&lt;br /&gt;
compile:&lt;br /&gt;
    [javac] Compiling 1 source file to /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes&lt;br /&gt;
&lt;br /&gt;
dex:&lt;br /&gt;
     [echo] Converting compiled files and external libraries into bin/classes.dex...&lt;br /&gt;
&lt;br /&gt;
package-resources:&lt;br /&gt;
     [echo] Packaging resources&lt;br /&gt;
 [aaptexec] Creating full resource package...&lt;br /&gt;
&lt;br /&gt;
debug-sign:&lt;br /&gt;
&lt;br /&gt;
package:&lt;br /&gt;
[apkbuilder] Creating .DemoActivity-debug-unaligned.apk and signing it with a debug key...&lt;br /&gt;
[apkbuilder] Using keystore: /Users/joelr/.android/debug.keystore&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes.dex =&amp;gt; classes.dex&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/libs/armeabi/libsanangeles.so =&amp;gt; lib/armeabi/libsanangeles.so&lt;br /&gt;
&lt;br /&gt;
debug:&lt;br /&gt;
     [echo] Running zip align on final apk...&lt;br /&gt;
     [echo] Debug Package: bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
BUILD SUCCESSFUL&lt;br /&gt;
Total time: 1 second&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, let&#039;s install the app on the device&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adb install -r bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
1107 KB/s (13707 bytes in 0.012s)&lt;br /&gt;
	pkg: /data/local/tmp/.DemoActivity-debug.apk&lt;br /&gt;
Success&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run the app click on the &amp;quot;tab&amp;quot; at the bottom of the Android emulator screen and then on the DemoActivity icon in the list of applications. Enjoy!&lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For [http://code.google.com/p/glesquake/ Quake], GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. lunch sdk-eng &amp;amp;&amp;amp; make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174912</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174912"/>
		<updated>2009-10-12T15:40:02Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* October 12, 2009 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 12, 2009 ==&lt;br /&gt;
&lt;br /&gt;
Via Chris Lord...&lt;br /&gt;
&lt;br /&gt;
The [http://hg.mozilla.org/incubator/offscreen headless branch of Mozilla that we work on] renders to system memory and it is up to the embedder to get this to a texture however they like. We have our own embedding library that uses this with Clutter&lt;br /&gt;
[http://git.clutter-project.org/?r=clutter-mozembed clutter-mozembed] and we just upload each changed region to the texture.&lt;br /&gt;
&lt;br /&gt;
A possible speed-up is to use a shared memory pixmap and texture-from-pixmap (or whatever the platform&#039;s equivalent is), which&lt;br /&gt;
would remove the need to copy from system to video memory.&lt;br /&gt;
&lt;br /&gt;
I wrote a (now out-dated, but still relevant) [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten guide on building the Moblin browser components] on my blog. There&#039;s also a [http://chrislord.net/files/moz-headless-screenshot.c short demo application I wrote] that just uses mozilla-headless alone to take a screenshot of a web-page. &lt;br /&gt;
&lt;br /&gt;
Unfortunately, there is no documentation beyond the standard Mozilla documentation and the source-code (and the above-mentioned links).&lt;br /&gt;
&lt;br /&gt;
I think the easiest way to port Firefox to android would be to write an android-backend (which could well be based on our headless backend) - I didn&#039;t think that the Android native development kit was fully featured enough to allow something like this though?&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
You can&#039;t run Firefox with the headless backend as it is, it&#039;s designed to be embedded and for libxul to be used. The headless backend is also heavily dependent on GLib (for the main loop, signals and idle handlers).&lt;br /&gt;
&lt;br /&gt;
If you wanted to run Firefox, you&#039;d have to write a new backend, or modify an existing one, to provide the application framework. In the gtk2 and headless backends, this is GLib-based. The Gtk2 backend creates a GtkWindow and that is how the user sees and interacts with the application. On the headless backend, there is no visible window. It can only be used for embedding via libxul.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
Chris has a [http://chrislord.net/files/fosdem-09-slides.odp presentation] that explains the headless branch a bit and [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten instructions on how to build it].&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building and running the OpenGL ES NDK example == &lt;br /&gt;
&lt;br /&gt;
Here&#039;s how to build and run the san-angeles application from NDK 1.6. This program demonstrates how to use a GLSurfaceView from Java along with native OpenGL calls to perform frame rendering.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cd /Volumes/android/mydroid/&lt;br /&gt;
. build/envsetup.sh &lt;br /&gt;
including vendor/aosp/vendorsetup.sh&lt;br /&gt;
lunch sdk-eng&lt;br /&gt;
&lt;br /&gt;
============================================&lt;br /&gt;
PLATFORM_VERSION_CODENAME=REL&lt;br /&gt;
PLATFORM_VERSION=1.6&lt;br /&gt;
TARGET_PRODUCT=sdk&lt;br /&gt;
TARGET_BUILD_VARIANT=eng&lt;br /&gt;
TARGET_SIMULATOR=false&lt;br /&gt;
TARGET_BUILD_TYPE=release&lt;br /&gt;
TARGET_ARCH=arm&lt;br /&gt;
HOST_ARCH=x86&lt;br /&gt;
HOST_OS=darwin&lt;br /&gt;
HOST_BUILD_TYPE=release&lt;br /&gt;
BUILD_ID=Donut&lt;br /&gt;
============================================&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First, we need to build the shared library of native code &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/work/android/android-ndk-1.6_r1/&lt;br /&gt;
build/host-setup.sh&lt;br /&gt;
make APP=san-angeles&lt;br /&gt;
&lt;br /&gt;
Android NDK: Building for application &#039;san-angeles&#039;    &lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/importgl.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/demo.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/app-android.c&lt;br /&gt;
SharedLibrary  : libsanangeles.so&lt;br /&gt;
Install        : libsanangeles.so =&amp;gt; apps/san-angeles/project/libs/armeabi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we need to make sure we can build the Java portion of the project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android update project --path apps/san-angeles/project&lt;br /&gt;
&lt;br /&gt;
Updated local.properties&lt;br /&gt;
File build.xml is too old and needs to be updated.&lt;br /&gt;
Added file apps/san-angeles/project/build.xml&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, lets build the debug release of project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd apps/san-angeles/project/&lt;br /&gt;
ant debug&lt;br /&gt;
&lt;br /&gt;
Buildfile: build.xml&lt;br /&gt;
    [setup] Project Target: Android 1.6&lt;br /&gt;
    [setup] API level: 4&lt;br /&gt;
&lt;br /&gt;
dirs:&lt;br /&gt;
     [echo] Creating output directories if needed...&lt;br /&gt;
&lt;br /&gt;
resource-src:&lt;br /&gt;
     [echo] Generating R.java / Manifest.java from the resources...&lt;br /&gt;
&lt;br /&gt;
aidl:&lt;br /&gt;
     [echo] Compiling aidl files into Java classes...&lt;br /&gt;
&lt;br /&gt;
compile:&lt;br /&gt;
    [javac] Compiling 1 source file to /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes&lt;br /&gt;
&lt;br /&gt;
dex:&lt;br /&gt;
     [echo] Converting compiled files and external libraries into bin/classes.dex...&lt;br /&gt;
&lt;br /&gt;
package-resources:&lt;br /&gt;
     [echo] Packaging resources&lt;br /&gt;
 [aaptexec] Creating full resource package...&lt;br /&gt;
&lt;br /&gt;
debug-sign:&lt;br /&gt;
&lt;br /&gt;
package:&lt;br /&gt;
[apkbuilder] Creating .DemoActivity-debug-unaligned.apk and signing it with a debug key...&lt;br /&gt;
[apkbuilder] Using keystore: /Users/joelr/.android/debug.keystore&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes.dex =&amp;gt; classes.dex&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/libs/armeabi/libsanangeles.so =&amp;gt; lib/armeabi/libsanangeles.so&lt;br /&gt;
&lt;br /&gt;
debug:&lt;br /&gt;
     [echo] Running zip align on final apk...&lt;br /&gt;
     [echo] Debug Package: bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
BUILD SUCCESSFUL&lt;br /&gt;
Total time: 1 second&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, let&#039;s install the app on the device&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adb install -r bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
1107 KB/s (13707 bytes in 0.012s)&lt;br /&gt;
	pkg: /data/local/tmp/.DemoActivity-debug.apk&lt;br /&gt;
Success&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run the app click on the &amp;quot;tab&amp;quot; at the bottom of the Android emulator screen and then on the DemoActivity icon in the list of applications. Enjoy!&lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For [http://code.google.com/p/glesquake/ Quake], GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. lunch sdk-eng &amp;amp;&amp;amp; make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174897</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174897"/>
		<updated>2009-10-12T12:41:59Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* October 12, 2009 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 12, 2009 ==&lt;br /&gt;
&lt;br /&gt;
Via Chris Lord...&lt;br /&gt;
&lt;br /&gt;
The [http://hg.mozilla.org/incubator/offscreen headless branch of Mozilla that we work on] renders to system memory and it is up to the embedder to get this to a texture however they like. We have our own embedding library that uses this with Clutter&lt;br /&gt;
[http://git.clutter-project.org/?r=clutter-mozembed clutter-mozembed] and we just upload each changed region to the texture.&lt;br /&gt;
&lt;br /&gt;
A possible speed-up is to use a shared memory pixmap and texture-from-pixmap (or whatever the platform&#039;s equivalent is), which&lt;br /&gt;
would remove the need to copy from system to video memory.&lt;br /&gt;
&lt;br /&gt;
I wrote a (now out-dated, but still relevant) [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten guide on building the Moblin browser components] on my blog. There&#039;s also a [http://chrislord.net/files/moz-headless-screenshot.c short demo application I wrote] that just uses mozilla-headless alone to take a screenshot of a web-page. &lt;br /&gt;
&lt;br /&gt;
Unfortunately, there is no documentation beyond the standard Mozilla documentation and the source-code (and the above-mentioned links).&lt;br /&gt;
&lt;br /&gt;
I think the easiest way to port Firefox to android would be to write an android-backend (which could well be based on our headless backend) - I didn&#039;t think that the Android native development kit was fully featured enough to allow something like this though?&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
You can&#039;t run Firefox with the headless backend as it is, it&#039;s designed to be embedded and for libxul to be used. The headless backend is also heavily dependent on GLib (for the main loop, signals and idle handlers).&lt;br /&gt;
&lt;br /&gt;
If you wanted to run Firefox, you&#039;d have to write a new backend, or modify an existing one, to provide the application framework. In the gtk2 and headless backends, this is GLib-based. The Gtk2 backend creates a GtkWindow and that is how the user sees and interacts with the application. On the headless backend, there is no visible window. It can only be used for embedding via libxul.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
Chris has a [http://chrislord.net/files/fosdem-09-slides.odp presentation] that explains the headless branch a bit.&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building and running the OpenGL ES NDK example == &lt;br /&gt;
&lt;br /&gt;
Here&#039;s how to build and run the san-angeles application from NDK 1.6. This program demonstrates how to use a GLSurfaceView from Java along with native OpenGL calls to perform frame rendering.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cd /Volumes/android/mydroid/&lt;br /&gt;
. build/envsetup.sh &lt;br /&gt;
including vendor/aosp/vendorsetup.sh&lt;br /&gt;
lunch sdk-eng&lt;br /&gt;
&lt;br /&gt;
============================================&lt;br /&gt;
PLATFORM_VERSION_CODENAME=REL&lt;br /&gt;
PLATFORM_VERSION=1.6&lt;br /&gt;
TARGET_PRODUCT=sdk&lt;br /&gt;
TARGET_BUILD_VARIANT=eng&lt;br /&gt;
TARGET_SIMULATOR=false&lt;br /&gt;
TARGET_BUILD_TYPE=release&lt;br /&gt;
TARGET_ARCH=arm&lt;br /&gt;
HOST_ARCH=x86&lt;br /&gt;
HOST_OS=darwin&lt;br /&gt;
HOST_BUILD_TYPE=release&lt;br /&gt;
BUILD_ID=Donut&lt;br /&gt;
============================================&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First, we need to build the shared library of native code &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/work/android/android-ndk-1.6_r1/&lt;br /&gt;
build/host-setup.sh&lt;br /&gt;
make APP=san-angeles&lt;br /&gt;
&lt;br /&gt;
Android NDK: Building for application &#039;san-angeles&#039;    &lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/importgl.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/demo.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/app-android.c&lt;br /&gt;
SharedLibrary  : libsanangeles.so&lt;br /&gt;
Install        : libsanangeles.so =&amp;gt; apps/san-angeles/project/libs/armeabi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we need to make sure we can build the Java portion of the project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android update project --path apps/san-angeles/project&lt;br /&gt;
&lt;br /&gt;
Updated local.properties&lt;br /&gt;
File build.xml is too old and needs to be updated.&lt;br /&gt;
Added file apps/san-angeles/project/build.xml&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, lets build the debug release of project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd apps/san-angeles/project/&lt;br /&gt;
ant debug&lt;br /&gt;
&lt;br /&gt;
Buildfile: build.xml&lt;br /&gt;
    [setup] Project Target: Android 1.6&lt;br /&gt;
    [setup] API level: 4&lt;br /&gt;
&lt;br /&gt;
dirs:&lt;br /&gt;
     [echo] Creating output directories if needed...&lt;br /&gt;
&lt;br /&gt;
resource-src:&lt;br /&gt;
     [echo] Generating R.java / Manifest.java from the resources...&lt;br /&gt;
&lt;br /&gt;
aidl:&lt;br /&gt;
     [echo] Compiling aidl files into Java classes...&lt;br /&gt;
&lt;br /&gt;
compile:&lt;br /&gt;
    [javac] Compiling 1 source file to /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes&lt;br /&gt;
&lt;br /&gt;
dex:&lt;br /&gt;
     [echo] Converting compiled files and external libraries into bin/classes.dex...&lt;br /&gt;
&lt;br /&gt;
package-resources:&lt;br /&gt;
     [echo] Packaging resources&lt;br /&gt;
 [aaptexec] Creating full resource package...&lt;br /&gt;
&lt;br /&gt;
debug-sign:&lt;br /&gt;
&lt;br /&gt;
package:&lt;br /&gt;
[apkbuilder] Creating .DemoActivity-debug-unaligned.apk and signing it with a debug key...&lt;br /&gt;
[apkbuilder] Using keystore: /Users/joelr/.android/debug.keystore&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes.dex =&amp;gt; classes.dex&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/libs/armeabi/libsanangeles.so =&amp;gt; lib/armeabi/libsanangeles.so&lt;br /&gt;
&lt;br /&gt;
debug:&lt;br /&gt;
     [echo] Running zip align on final apk...&lt;br /&gt;
     [echo] Debug Package: bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
BUILD SUCCESSFUL&lt;br /&gt;
Total time: 1 second&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, let&#039;s install the app on the device&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adb install -r bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
1107 KB/s (13707 bytes in 0.012s)&lt;br /&gt;
	pkg: /data/local/tmp/.DemoActivity-debug.apk&lt;br /&gt;
Success&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run the app click on the &amp;quot;tab&amp;quot; at the bottom of the Android emulator screen and then on the DemoActivity icon in the list of applications. Enjoy!&lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For [http://code.google.com/p/glesquake/ Quake], GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. lunch sdk-eng &amp;amp;&amp;amp; make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174888</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174888"/>
		<updated>2009-10-12T10:11:36Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Current status */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 12, 2009 ==&lt;br /&gt;
&lt;br /&gt;
Via Chris Lord...&lt;br /&gt;
&lt;br /&gt;
The [http://hg.mozilla.org/incubator/offscreen headless branch of Mozilla that we work on] renders to system memory and it is up to the embedder to get this to a texture however they like. We have our own embedding library that uses this with Clutter&lt;br /&gt;
[http://git.clutter-project.org/?r=clutter-mozembed clutter-mozembed] and we just upload each changed region to the texture.&lt;br /&gt;
&lt;br /&gt;
A possible speed-up is to use a shared memory pixmap and texture-from-pixmap (or whatever the platform&#039;s equivalent is), which&lt;br /&gt;
would remove the need to copy from system to video memory.&lt;br /&gt;
&lt;br /&gt;
I wrote a (now out-dated, but still relevant) [http://chrislord.net/blog/Software/building-moblin-web-browser.enlighten guide on building the Moblin browser components] on my blog. There&#039;s also a [http://chrislord.net/files/moz-headless-screenshot.c short demo application I wrote] that just uses mozilla-headless alone to take a screenshot of a web-page. &lt;br /&gt;
&lt;br /&gt;
Unfortunately, there is no documentation beyond the standard Mozilla documentation and the source-code (and the above-mentioned links).&lt;br /&gt;
&lt;br /&gt;
I think the easiest way to port Firefox to android would be to write an android-backend (which could well be based on our headless backend) - I didn&#039;t think that the Android native development kit was fully featured enough to allow something like this though?&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building and running the OpenGL ES NDK example == &lt;br /&gt;
&lt;br /&gt;
Here&#039;s how to build and run the san-angeles application from NDK 1.6. This program demonstrates how to use a GLSurfaceView from Java along with native OpenGL calls to perform frame rendering.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cd /Volumes/android/mydroid/&lt;br /&gt;
. build/envsetup.sh &lt;br /&gt;
including vendor/aosp/vendorsetup.sh&lt;br /&gt;
lunch sdk-eng&lt;br /&gt;
&lt;br /&gt;
============================================&lt;br /&gt;
PLATFORM_VERSION_CODENAME=REL&lt;br /&gt;
PLATFORM_VERSION=1.6&lt;br /&gt;
TARGET_PRODUCT=sdk&lt;br /&gt;
TARGET_BUILD_VARIANT=eng&lt;br /&gt;
TARGET_SIMULATOR=false&lt;br /&gt;
TARGET_BUILD_TYPE=release&lt;br /&gt;
TARGET_ARCH=arm&lt;br /&gt;
HOST_ARCH=x86&lt;br /&gt;
HOST_OS=darwin&lt;br /&gt;
HOST_BUILD_TYPE=release&lt;br /&gt;
BUILD_ID=Donut&lt;br /&gt;
============================================&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First, we need to build the shared library of native code &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/work/android/android-ndk-1.6_r1/&lt;br /&gt;
build/host-setup.sh&lt;br /&gt;
make APP=san-angeles&lt;br /&gt;
&lt;br /&gt;
Android NDK: Building for application &#039;san-angeles&#039;    &lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/importgl.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/demo.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/app-android.c&lt;br /&gt;
SharedLibrary  : libsanangeles.so&lt;br /&gt;
Install        : libsanangeles.so =&amp;gt; apps/san-angeles/project/libs/armeabi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we need to make sure we can build the Java portion of the project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android update project --path apps/san-angeles/project&lt;br /&gt;
&lt;br /&gt;
Updated local.properties&lt;br /&gt;
File build.xml is too old and needs to be updated.&lt;br /&gt;
Added file apps/san-angeles/project/build.xml&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, lets build the debug release of project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd apps/san-angeles/project/&lt;br /&gt;
ant debug&lt;br /&gt;
&lt;br /&gt;
Buildfile: build.xml&lt;br /&gt;
    [setup] Project Target: Android 1.6&lt;br /&gt;
    [setup] API level: 4&lt;br /&gt;
&lt;br /&gt;
dirs:&lt;br /&gt;
     [echo] Creating output directories if needed...&lt;br /&gt;
&lt;br /&gt;
resource-src:&lt;br /&gt;
     [echo] Generating R.java / Manifest.java from the resources...&lt;br /&gt;
&lt;br /&gt;
aidl:&lt;br /&gt;
     [echo] Compiling aidl files into Java classes...&lt;br /&gt;
&lt;br /&gt;
compile:&lt;br /&gt;
    [javac] Compiling 1 source file to /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes&lt;br /&gt;
&lt;br /&gt;
dex:&lt;br /&gt;
     [echo] Converting compiled files and external libraries into bin/classes.dex...&lt;br /&gt;
&lt;br /&gt;
package-resources:&lt;br /&gt;
     [echo] Packaging resources&lt;br /&gt;
 [aaptexec] Creating full resource package...&lt;br /&gt;
&lt;br /&gt;
debug-sign:&lt;br /&gt;
&lt;br /&gt;
package:&lt;br /&gt;
[apkbuilder] Creating .DemoActivity-debug-unaligned.apk and signing it with a debug key...&lt;br /&gt;
[apkbuilder] Using keystore: /Users/joelr/.android/debug.keystore&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes.dex =&amp;gt; classes.dex&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/libs/armeabi/libsanangeles.so =&amp;gt; lib/armeabi/libsanangeles.so&lt;br /&gt;
&lt;br /&gt;
debug:&lt;br /&gt;
     [echo] Running zip align on final apk...&lt;br /&gt;
     [echo] Debug Package: bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
BUILD SUCCESSFUL&lt;br /&gt;
Total time: 1 second&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, let&#039;s install the app on the device&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adb install -r bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
1107 KB/s (13707 bytes in 0.012s)&lt;br /&gt;
	pkg: /data/local/tmp/.DemoActivity-debug.apk&lt;br /&gt;
Success&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run the app click on the &amp;quot;tab&amp;quot; at the bottom of the Android emulator screen and then on the DemoActivity icon in the list of applications. Enjoy!&lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For [http://code.google.com/p/glesquake/ Quake], GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. lunch sdk-eng &amp;amp;&amp;amp; make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174538</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174538"/>
		<updated>2009-10-09T14:55:55Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Android Notes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 7, 2009 ==&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building and running the OpenGL ES NDK example == &lt;br /&gt;
&lt;br /&gt;
Here&#039;s how to build and run the san-angeles application from NDK 1.6. This program demonstrates how to use a GLSurfaceView from Java along with native OpenGL calls to perform frame rendering.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
cd /Volumes/android/mydroid/&lt;br /&gt;
. build/envsetup.sh &lt;br /&gt;
including vendor/aosp/vendorsetup.sh&lt;br /&gt;
lunch sdk-eng&lt;br /&gt;
&lt;br /&gt;
============================================&lt;br /&gt;
PLATFORM_VERSION_CODENAME=REL&lt;br /&gt;
PLATFORM_VERSION=1.6&lt;br /&gt;
TARGET_PRODUCT=sdk&lt;br /&gt;
TARGET_BUILD_VARIANT=eng&lt;br /&gt;
TARGET_SIMULATOR=false&lt;br /&gt;
TARGET_BUILD_TYPE=release&lt;br /&gt;
TARGET_ARCH=arm&lt;br /&gt;
HOST_ARCH=x86&lt;br /&gt;
HOST_OS=darwin&lt;br /&gt;
HOST_BUILD_TYPE=release&lt;br /&gt;
BUILD_ID=Donut&lt;br /&gt;
============================================&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First, we need to build the shared library of native code &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/work/android/android-ndk-1.6_r1/&lt;br /&gt;
build/host-setup.sh&lt;br /&gt;
make APP=san-angeles&lt;br /&gt;
&lt;br /&gt;
Android NDK: Building for application &#039;san-angeles&#039;    &lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/importgl.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/demo.c&lt;br /&gt;
Compile thumb  : sanangeles &amp;lt;= apps/san-angeles/project/jni/app-android.c&lt;br /&gt;
SharedLibrary  : libsanangeles.so&lt;br /&gt;
Install        : libsanangeles.so =&amp;gt; apps/san-angeles/project/libs/armeabi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we need to make sure we can build the Java portion of the project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android update project --path apps/san-angeles/project&lt;br /&gt;
&lt;br /&gt;
Updated local.properties&lt;br /&gt;
File build.xml is too old and needs to be updated.&lt;br /&gt;
Added file apps/san-angeles/project/build.xml&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, lets build the debug release of project&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd apps/san-angeles/project/&lt;br /&gt;
ant debug&lt;br /&gt;
&lt;br /&gt;
Buildfile: build.xml&lt;br /&gt;
    [setup] Project Target: Android 1.6&lt;br /&gt;
    [setup] API level: 4&lt;br /&gt;
&lt;br /&gt;
dirs:&lt;br /&gt;
     [echo] Creating output directories if needed...&lt;br /&gt;
&lt;br /&gt;
resource-src:&lt;br /&gt;
     [echo] Generating R.java / Manifest.java from the resources...&lt;br /&gt;
&lt;br /&gt;
aidl:&lt;br /&gt;
     [echo] Compiling aidl files into Java classes...&lt;br /&gt;
&lt;br /&gt;
compile:&lt;br /&gt;
    [javac] Compiling 1 source file to /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes&lt;br /&gt;
&lt;br /&gt;
dex:&lt;br /&gt;
     [echo] Converting compiled files and external libraries into bin/classes.dex...&lt;br /&gt;
&lt;br /&gt;
package-resources:&lt;br /&gt;
     [echo] Packaging resources&lt;br /&gt;
 [aaptexec] Creating full resource package...&lt;br /&gt;
&lt;br /&gt;
debug-sign:&lt;br /&gt;
&lt;br /&gt;
package:&lt;br /&gt;
[apkbuilder] Creating .DemoActivity-debug-unaligned.apk and signing it with a debug key...&lt;br /&gt;
[apkbuilder] Using keystore: /Users/joelr/.android/debug.keystore&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/bin/classes.dex =&amp;gt; classes.dex&lt;br /&gt;
[apkbuilder] /Users/joelr/Work/android/android-ndk-1.6_r1/apps/san-angeles/project/libs/armeabi/libsanangeles.so =&amp;gt; lib/armeabi/libsanangeles.so&lt;br /&gt;
&lt;br /&gt;
debug:&lt;br /&gt;
     [echo] Running zip align on final apk...&lt;br /&gt;
     [echo] Debug Package: bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
BUILD SUCCESSFUL&lt;br /&gt;
Total time: 1 second&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, let&#039;s install the app on the device&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adb install -r bin/.DemoActivity-debug.apk&lt;br /&gt;
&lt;br /&gt;
1107 KB/s (13707 bytes in 0.012s)&lt;br /&gt;
	pkg: /data/local/tmp/.DemoActivity-debug.apk&lt;br /&gt;
Success&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run the app click on the &amp;quot;tab&amp;quot; at the bottom of the Android emulator screen and then on the DemoActivity icon in the list of applications. Enjoy!&lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For [http://code.google.com/p/glesquake/ Quake], GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. lunch sdk-eng &amp;amp;&amp;amp; make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174533</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174533"/>
		<updated>2009-10-09T13:46:20Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Building Android on Snow Leopard */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 7, 2009 ==&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For [http://code.google.com/p/glesquake/ Quake], GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. lunch sdk-eng &amp;amp;&amp;amp; make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174373</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174373"/>
		<updated>2009-10-08T16:41:14Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Drawing and input from native code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 7, 2009 ==&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For [http://code.google.com/p/glesquake/ Quake], GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
lunch generic-eng &amp;amp;&amp;amp; emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174372</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174372"/>
		<updated>2009-10-08T16:40:09Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Android Notes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 7, 2009 ==&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Drawing and input from native code ==&lt;br /&gt;
&lt;br /&gt;
Via Jack Palevich...&lt;br /&gt;
&lt;br /&gt;
Input is done by subclassing a view, and override the various input methods.  Make sure your view can get focus, using setFocusableInTouchMode(true);  Otherwise you won&#039;t get input events. You could use any View class as your base class, but I suggest that you subclass GLSurfaceView because that makes it easier to use OpenGL graphics for drawing. &lt;br /&gt;
&lt;br /&gt;
Probably the fastest way to get output from native code is done using OpenGL ES, which is newly available in NDK 1.6. Create a texture the size of the  screen ( it has to be a power of two on each side, so 512 x 256 if your screen is 320 x 240.) Then update the texture and render it to the screen as a screen aligned quad. &lt;br /&gt;
&lt;br /&gt;
For native OpenGL ES APIs the drawing surface is implicit in the thread. For Quake, GLSurfaceView&#039;s rendering thread sets up the context and calls the&lt;br /&gt;
QuakeView&#039;s Renderer, which calls the native code, which makes the native GL calls.&lt;br /&gt;
&lt;br /&gt;
Because the context is implicit in the thread, there&#039;s nothing that needs to be passed between Java and native code.&lt;br /&gt;
&lt;br /&gt;
The downside of this approach is that you can&#039;t wrap the native GL calls as easily as you can wrap the JSR 239 Java OpenGL APIs. It&#039;s sometimes useful&lt;br /&gt;
to wrap the GL APIs to keep track of the matrix stack, or log debugging messages, or check for error messages.&lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
lunch generic-eng &amp;amp;&amp;amp; emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174213</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174213"/>
		<updated>2009-10-07T21:19:17Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Building Android on Snow Leopard */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 7, 2009 ==&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
lunch generic-eng &amp;amp;&amp;amp; emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174211</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174211"/>
		<updated>2009-10-07T21:17:24Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Building Android on Snow Leopard */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 7, 2009 ==&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
pushd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
pushd out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/lib&lt;br /&gt;
ln -s x86 x86_64 &amp;amp;&amp;amp; popd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
     &lt;br /&gt;
android list avd&lt;br /&gt;
&lt;br /&gt;
Available Android Virtual Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_SDK=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86&lt;br /&gt;
export AND_BIN=$AND_SDK/tools&lt;br /&gt;
export AND_IMG=$AND_SDK/platforms/android-1.6/images&lt;br /&gt;
export AND_KERNEL=$AND_IMG/kernel-qemu&lt;br /&gt;
export PATH=$PATH:$AND_BIN&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
cd /Volumes/android/mydroid&lt;br /&gt;
. ./build/envsetup.sh&lt;br /&gt;
lunch generic-eng &amp;amp;&amp;amp; emulator&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see home screen in a minute or less. &lt;br /&gt;
&lt;br /&gt;
You can also run the emulator in verbose mode if you want to troubleshoot or just see lots of interesting output, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
emulator -verbose -logcat &amp;quot;*:v&amp;quot;&lt;br /&gt;
&lt;br /&gt;
emulator: found Android build root: /Volumes/android/mydroid&lt;br /&gt;
emulator: found Android build out:  /Volumes/android/mydroid/out/target/product/generic&lt;br /&gt;
emulator:     locking user data image at /Volumes/android/mydroid/out/target/product/generic/userdata-qemu.img&lt;br /&gt;
emulator: selecting default skin name &#039;HVGA&#039;&lt;br /&gt;
emulator: autoconfig: -skin HVGA&lt;br /&gt;
emulator: autoconfig: -skindir /Volumes/android/mydroid/development/emulator/skins&lt;br /&gt;
emulator: keyset loaded from: /Users/joelr/.android/default.keyset&lt;br /&gt;
emulator: trying to load skin file &#039;/Volumes/android/mydroid/development/emulator/skins/HVGA/layout&#039;&lt;br /&gt;
emulator: skin network speed: &#039;full&#039;&lt;br /&gt;
emulator: skin network delay: &#039;none&#039;&lt;br /&gt;
emulator: no SD Card image at &#039;/Volumes/android/mydroid/out/target/product/generic/sdcard.img&#039;&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: registered &#039;boot-properties&#039; qemud service&lt;br /&gt;
emulator: Adding boot property: &#039;qemu.sf.lcd_density&#039; = &#039;160&#039;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174132</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174132"/>
		<updated>2009-10-07T17:59:34Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Building Android on Snow Leopard */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 7, 2009 ==&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. make sdk&lt;br /&gt;
&lt;br /&gt;
You should see something like this if everything goes well&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ls out/host/darwin-x86/sdk/&lt;br /&gt;
android-sdk_eng.joelr_mac-x86		sdk_deps.mk&lt;br /&gt;
android-sdk_eng.joelr_mac-x86.zip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more step is needed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PATH=$PATH:`pwd`/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools/&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; ln -s darwin-x86 darwin-x86_64&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything works&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
android list targets&lt;br /&gt;
&lt;br /&gt;
Available Android targets:&lt;br /&gt;
id: 1&lt;br /&gt;
     Name: Android 1.6&lt;br /&gt;
     Type: Platform&lt;br /&gt;
     API level: 4&lt;br /&gt;
     Revision: 1&lt;br /&gt;
     Skins: HVGA (default), QVGA, WVGA800, WVGA854&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_BIN=$AND_HOME/out/host/darwin-x86/sdk/android-sdk_eng.joelr_mac-x86/tools&lt;br /&gt;
export AND_PROD=$AND_HOME/out/target/product/generic&lt;br /&gt;
export AND_QEMU=$AND_HOME/prebuilt/android-arm/kernel/kernel-qemu&lt;br /&gt;
export AND_IMG=$AND_HOME/out/target/product/generic/userdata.img&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
&lt;br /&gt;
$AND_BIN/emulator -sysdir $AND_PROD -kernel $AND_QEMU -system $AND_IMG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174104</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174104"/>
		<updated>2009-10-07T16:57:42Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Building Android on Snow Leopard */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 7, 2009 ==&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply these changes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd system/core &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/system/core refs/changes/45/11845/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd external/qemu &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/external/qemu refs/changes/46/11846/2 &amp;amp;&amp;amp; cd ../..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/14/12014/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd prebuilt &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/prebuilt refs/changes/75/12075/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/74/12074/1 &amp;amp;&amp;amp; cd ..&lt;br /&gt;
cd build &amp;amp;&amp;amp; git pull git://android.git.kernel.org/platform/build refs/changes/93/12093/1 &amp;amp;&amp;amp; cd .. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. make&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_BIN=$AND_HOME/out/host/darwin-x86/bin&lt;br /&gt;
export AND_PROD=$AND_HOME/out/target/product/generic&lt;br /&gt;
export AND_QEMU=$AND_HOME/prebuilt/android-arm/kernel/kernel-qemu&lt;br /&gt;
export AND_IMG=$AND_HOME/out/target/product/generic/userdata.img&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
&lt;br /&gt;
$AND_BIN/emulator -sysdir $AND_PROD -kernel $AND_QEMU -system $AND_IMG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174102</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174102"/>
		<updated>2009-10-07T16:54:53Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Building Android on Snow Leopard */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 7, 2009 ==&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply [http://groups.google.com/group/android-platform/msg/efd76f9a3bd02a2b changes] making sure there spaces before &#039;&#039;refs&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
This almost works but resets the head each time. Both of the last two changes are needed but the Java one gets written over by the very last change. Also, changes downloaded this way get blown away on &#039;&#039;repo sync&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
repo download platform/system/core 11845/2&lt;br /&gt;
repo download platform/external/qemu 11846/2&lt;br /&gt;
repo download platform/prebuilt 12014/1&lt;br /&gt;
repo download platform/prebuilt 12075/1&lt;br /&gt;
repo download platform/build 12074/1&lt;br /&gt;
repo download platform/build 12093/1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. make&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_BIN=$AND_HOME/out/host/darwin-x86/bin&lt;br /&gt;
export AND_PROD=$AND_HOME/out/target/product/generic&lt;br /&gt;
export AND_QEMU=$AND_HOME/prebuilt/android-arm/kernel/kernel-qemu&lt;br /&gt;
export AND_IMG=$AND_HOME/out/target/product/generic/userdata.img&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
&lt;br /&gt;
$AND_BIN/emulator -sysdir $AND_PROD -kernel $AND_QEMU -system $AND_IMG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174063</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174063"/>
		<updated>2009-10-07T15:51:04Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Android Notes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 7, 2009 ==&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply [http://groups.google.com/group/android-platform/msg/efd76f9a3bd02a2b changes] making sure there spaces before &#039;&#039;refs&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
3. make&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_BIN=$AND_HOME/out/host/darwin-x86/bin&lt;br /&gt;
export AND_PROD=$AND_HOME/out/target/product/generic&lt;br /&gt;
export AND_QEMU=$AND_HOME/prebuilt/android-arm/kernel/kernel-qemu&lt;br /&gt;
export AND_IMG=$AND_HOME/out/target/product/generic/userdata.img&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
&lt;br /&gt;
$AND_BIN/emulator -sysdir $AND_PROD -kernel $AND_QEMU -system $AND_IMG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vlad&#039;s Android Notes == &lt;br /&gt;
&lt;br /&gt;
Can be found [https://wiki.mozilla.org/User:VladVukicevic/Android_Notes here].&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont&amp;diff=174062</id>
		<title>User:Joel Reymont</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont&amp;diff=174062"/>
		<updated>2009-10-07T15:48:32Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: Created page with &amp;#039;= [https://wiki.mozilla.org/User:Joel_Reymont/Android_Notes Android Notes] =  = [https://wiki.mozilla.org/Firefox/Projects/Startup_Time_Improvements/joelr_notes Firefox startup t…&amp;#039;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= [https://wiki.mozilla.org/User:Joel_Reymont/Android_Notes Android Notes] =&lt;br /&gt;
&lt;br /&gt;
= [https://wiki.mozilla.org/Firefox/Projects/Startup_Time_Improvements/joelr_notes Firefox startup time improvements] =&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174061</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174061"/>
		<updated>2009-10-07T15:46:42Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Building Android on Snow Leopard */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 7, 2009 ==&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply [http://groups.google.com/group/android-platform/msg/efd76f9a3bd02a2b changes] making sure there spaces before &#039;&#039;refs&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
3. make&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_BIN=$AND_HOME/out/host/darwin-x86/bin&lt;br /&gt;
export AND_PROD=$AND_HOME/out/target/product/generic&lt;br /&gt;
export AND_QEMU=$AND_HOME/prebuilt/android-arm/kernel/kernel-qemu&lt;br /&gt;
export AND_IMG=$AND_HOME/out/target/product/generic/userdata.img&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
&lt;br /&gt;
$AND_BIN/emulator -sysdir $AND_PROD -kernel $AND_QEMU -system $AND_IMG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174060</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174060"/>
		<updated>2009-10-07T15:43:35Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
== October 7, 2009 ==&lt;br /&gt;
&lt;br /&gt;
= Previous statuses =&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply [http://groups.google.com/group/android-platform/msg/efd76f9a3bd02a2b changes] making sure there spaces before &#039;&#039;refs&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
3. make&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_BIN=$AND_HOME/out/host/darwin-x86/bin&lt;br /&gt;
export AND_PROD=$AND_HOME/out/target/product/generic&lt;br /&gt;
export AND_QEMU=$AND_HOME/prebuilt/android-arm/kernel/kernel-qemu&lt;br /&gt;
export AND_IMG=$AND_HOME/out/target/product/generic/userdata.img&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
&lt;br /&gt;
$AND_BIN/emulator -system $AND_PROD -kernel $AND_QEMU -data $AND_IMG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174057</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174057"/>
		<updated>2009-10-07T15:42:43Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Building Android on Snow Leopard */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== October 7, 2009 ===&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;br /&gt;
&lt;br /&gt;
1. [http://source.android.com/download Get the sources].&lt;br /&gt;
&lt;br /&gt;
2. Apply [http://groups.google.com/group/android-platform/msg/efd76f9a3bd02a2b changes] making sure there spaces before &#039;&#039;refs&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
3. make&lt;br /&gt;
&lt;br /&gt;
4. You are set and you can now run the emulator, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export AND_HOME=/Volumes/android/mydroid&lt;br /&gt;
export AND_BIN=$AND_HOME/out/host/darwin-x86/bin&lt;br /&gt;
export AND_PROD=$AND_HOME/out/target/product/generic&lt;br /&gt;
export AND_QEMU=$AND_HOME/prebuilt/android-arm/kernel/kernel-qemu&lt;br /&gt;
export AND_IMG=$AND_HOME/out/target/product/generic/userdata.img&lt;br /&gt;
&lt;br /&gt;
hdiutil attach ~/work/android/android.dmg -mountpoint /Volumes/android&lt;br /&gt;
&lt;br /&gt;
$AND_BIN/emulator -system $AND_PROD -kernel $AND_QEMU -data $AND_IMG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174053</id>
		<title>User:Joel Reymont/Android Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Joel_Reymont/Android_Notes&amp;diff=174053"/>
		<updated>2009-10-07T15:36:45Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: Created page with &amp;#039;= Intro  =  This page collects my notes on porting Firefox to Android.  = Current status =  === October 7, 2009 ===  = Android Notes =   == Building Android on Snow Leopard ==&amp;#039;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
This page collects my notes on porting Firefox to Android.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== October 7, 2009 ===&lt;br /&gt;
&lt;br /&gt;
= Android Notes = &lt;br /&gt;
&lt;br /&gt;
== Building Android on Snow Leopard ==&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=170455</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=170455"/>
		<updated>2009-09-23T23:02:04Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* September 23, 2009 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 23, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== x86-64 ==== &lt;br /&gt;
&lt;br /&gt;
I now have x86-64 Firefox up and running on Snow Leopard. Josh Aas did all the work, I just [https://bugzilla.mozilla.org/show_bug.cgi?id=518435 put on the final touches]. &lt;br /&gt;
&lt;br /&gt;
==== A shiny new world ==== &lt;br /&gt;
&lt;br /&gt;
Damon thinks I should help Josh with the 64-bit port. 64-bit Trace Monkey gives us a [http://www.bailopan.net/blog/?p=595 20% improvement in speed] which beats the 5% DWARF improvement from -fomit-frame-pointer. &lt;br /&gt;
&lt;br /&gt;
I didn&#039;t know it was my birthday. I&#039;m leaving the 32-bit world behind. 64 bits here I come!&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 22, 2009 ===&lt;br /&gt;
&lt;br /&gt;
I have two bottlenecks on my plate, [https://bugzilla.mozilla.org/show_bug.cgi?id=517045 Bug 517045] and [https://bugzilla.mozilla.org/show_bug.cgi?id=517576 Bug 517576]. Both of them may not be possible to speed up significantly, not without a large research effort. The former requires consultation with the owners and the later requires me to become a layout expert.&lt;br /&gt;
&lt;br /&gt;
Benjamin Smedberg suggested taking care of DWARF symbols in breakpad as that will let us use the -fomit-frame-pointer gcc option. Omitting the frame pointer would result in at least a 5% overall speed up because a register will be freed on x86-32.&lt;br /&gt;
&lt;br /&gt;
DWARF is a [https://bugzilla.mozilla.org/showdependencygraph.cgi?id=464750 tree of dependent bugs], though, and Jim Blandy is working on them. Jim is a Linux guy, though, and also has ECMAScript 5 strict mode to take care of whereas I&#039;m strictly focused on performance optimization.&lt;br /&gt;
&lt;br /&gt;
I&#039;ll ask management to see if I can work on DWARF with Jim.&lt;br /&gt;
&lt;br /&gt;
=== September 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Wins ====&lt;br /&gt;
&lt;br /&gt;
Kudos to Masayuki for fixing [https://bugzilla.mozilla.org/show_bug.cgi?id=517549 Bug 517549]. It&#039;s hard to believe but it looks like our Mac Ts [http://graphs.mozilla.org/graph.html#tests=[{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22169%22},{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22173%22},{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22178%22}]&amp;amp;sel=1252833380,1253542320 went down 30%] and it was only 12.3% of my startup. I wonder what happens when [https://bugzilla.mozilla.org/show_bug.cgi?id=517576 Bug 517576] gets fixed, that&#039;s 21% of my startup!&lt;br /&gt;
&lt;br /&gt;
One other thing I&#039;m wondering about... What if all the bottlenecks I find will get fixed by someone else? Damon wants me to write code!!! &lt;br /&gt;
&lt;br /&gt;
=== September 16, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== That mysterious forking ====&lt;br /&gt;
&lt;br /&gt;
Apparently, Firefox forks the first time after a build to rebuild caches, etc. Need to make sure to profile from the 2nd run on. This forking behavior baffled me when I started with DTrace.&lt;br /&gt;
&lt;br /&gt;
==== I&#039;m an idiot ====&lt;br /&gt;
&lt;br /&gt;
I spent a month becoming an expert on DTrace, only to realize that it&#039;s not very useful to get a global picture of the bottlenecks because the overhead of tracing everything is so high! &lt;br /&gt;
&lt;br /&gt;
Shark is a much better tool to get a global picture, specially using &amp;quot;Time profile all states&amp;quot; which allocates time spent blocking to the calling function. I overlooked this initially since I did not zero in on the right thread, the one that has &#039;&#039;start&#039;&#039; and &#039;&#039;XRE_main&#039;&#039; or &#039;&#039;exit&#039;&#039;. Without this it looks like Firefox is spending most of its time waiting on threads and Mach messages.&lt;br /&gt;
&lt;br /&gt;
==== Timing startup ====&lt;br /&gt;
&lt;br /&gt;
A clear picture courtesy of Shark&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	0.0%	92.8%	firefox-bin	start&lt;br /&gt;
	0.0%	92.8%	firefox-bin	 main&lt;br /&gt;
	0.0%	91.6%	XUL	  XRE_main&lt;br /&gt;
	0.0%	40.8%	XUL	   nsAppStartup::CreateHiddenWindow()&lt;br /&gt;
	0.0%	34.7%	XUL	   ScopedXPCOMStartup::Initialize()&lt;br /&gt;
	0.0%	6.4%	XUL	   ScopedXPCOMStartup::~ScopedXPCOMStartup()&lt;br /&gt;
	0.0%	3.4%	XUL	   ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport*)&lt;br /&gt;
	0.0%	2.4%	XUL	   nsXPTCStubBase::Stub3()&lt;br /&gt;
	0.0%	0.8%	XUL	   nsAppStartupNotifier::Observe(nsISupports*, char const*, unsigned short const*)&lt;br /&gt;
	0.0%	0.8%	HIToolbox	   GetCurrentEventKeyModifiers&lt;br /&gt;
	0.0%	0.6%	XUL	   nsXREDirProvider::DoStartup()&lt;br /&gt;
	0.0%	0.5%	XUL	   RemoveComponentRegistries(nsIFile*, nsIFile*, int)&lt;br /&gt;
	0.0%	0.4%	XUL	   NS_NewToolkitProfileService(nsIToolkitProfileService**)&lt;br /&gt;
	0.0%	0.3%	XUL	   nsToolkitProfile::Lock(nsIProfileUnlocker**, nsIProfileLock**)&lt;br /&gt;
	0.0%	0.1%	XUL	   WriteVersion(nsIFile*, nsCString const&amp;amp;, nsCString const&amp;amp;, nsIFile*, nsIFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   nsINIParser_internal::Init(nsILocalFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   LaunchChildMac&lt;br /&gt;
	0.0%	0.4%	XUL	  XRE_GetBinaryPath&lt;br /&gt;
	0.3%	0.4%	XUL	  XRE_CreateAppData&lt;br /&gt;
	0.4%	0.4%	XUL	  NS_LogInit_P&lt;br /&gt;
	0.0%	6.2%	dyld	_dyld_start&lt;br /&gt;
	1.0%	1.0%	libSystem.B.dylib	_exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Breaking startup into smaller chunks ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: I really think that &amp;quot;Ts&amp;quot; is still much too large of a chunk to make meaningful improvements on&lt;br /&gt;
bsmedberg:joelr: in order to make meaninful discoveries, I think you have to break startup down into pieces and then maybe improve each piece&lt;br /&gt;
joelr:bsmedberg: i&#039;m listening&lt;br /&gt;
bsmedberg:well, you&#039;ve got various stuff that happens up until you start the event loop&lt;br /&gt;
bsmedberg:breaking XRE_main into phases up until nsAppStartup::Run would be interesting&lt;br /&gt;
bsmedberg:I still haven&#039;t seen a graph or anything of how we break down&lt;br /&gt;
bsmedberg:joelr: I think stepping through in a debugger might give you a better sense of what&#039;s going on (up until Run()) than profiles would&lt;br /&gt;
bsmedberg:even if you broke things up into &amp;quot;from main() to the beginning of event loop&amp;quot; and &amp;quot;after the event loop starts&amp;quot; that would be more interesting&lt;br /&gt;
bsmedberg:joelr: and then within the first chunk, timing NS_InitXPCOM, the extension manager bits, chromereg startup&lt;br /&gt;
bsmedberg:joelr: I think this intersects with some of the startup-timeline stuff taras was doing&lt;br /&gt;
joelr:bsmedberg: what are the functions for &amp;quot;extension manager bits&amp;quot; and &amp;quot;chromereg startup&amp;quot;?&lt;br /&gt;
bsmedberg:joelr: basically from http://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#2607 to #3453&lt;br /&gt;
joelr:bsmedberg: thanks for the suggestion, i&#039;ll do that&lt;br /&gt;
bsmedberg:joelr: #3382 to #3408 or so&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XUL reflow ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:joelr: so I&#039;m still wondering about some of the reflow stuff&lt;br /&gt;
bz:joelr: I know it&#039;s hard, but that&#039;s why no one&#039;s really dived into it yet&lt;br /&gt;
bz:joelr: and I&#039;d love to know whether we do in fact end up looping significantly in sprocket layout during startup, for example&lt;br /&gt;
joelr:bz: i&#039;m still wondering about reflow myself but i&#039;m not quite ready to tackle it yet&lt;br /&gt;
joelr:bz: don&#039;t know enough&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Shark tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== Expanding the call tree === &lt;br /&gt;
&lt;br /&gt;
Alt-Click does it.&lt;br /&gt;
&lt;br /&gt;
=== CHUD signposts on Snow Leopard ===&lt;br /&gt;
&lt;br /&gt;
There are no CHUD header files on Snow Leopard. If you&#039;re only interest is in emitting signposts, the easiest thing for you to do is switch to the syscall method instead.  That&#039;ll also mean you won&#039;t have to link against the CHUD framework. The full details are in the Shark User Guide, but in brief:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int err = syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, &amp;lt;your code number&amp;gt;) | &amp;lt;type&amp;gt;, arg1, arg2, arg3, arg4);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Types are DBG_FUNC_START, DBG_FUNC_END and DBG_FUNC_NONE (for point signposts).&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to include &amp;lt;sys/kdebug.h&amp;gt; and &amp;lt;sys/syscall.h&amp;gt; for the necessary macros and function.&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=170189</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=170189"/>
		<updated>2009-09-23T13:07:30Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* A shiny new world */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 23, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== A shiny new world ==== &lt;br /&gt;
&lt;br /&gt;
Damon thinks I should help Josh with the 64-bit port. 64-bit Trace Monkey gives us a [http://www.bailopan.net/blog/?p=595 20% improvement in speed] which beats the 5% DWARF improvement from -fomit-frame-pointer. &lt;br /&gt;
&lt;br /&gt;
I didn&#039;t know it was my birthday. I&#039;m leaving the 32-bit world behind. 64 bits here I come!&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 22, 2009 ===&lt;br /&gt;
&lt;br /&gt;
I have two bottlenecks on my plate, [https://bugzilla.mozilla.org/show_bug.cgi?id=517045 Bug 517045] and [https://bugzilla.mozilla.org/show_bug.cgi?id=517576 Bug 517576]. Both of them may not be possible to speed up significantly, not without a large research effort. The former requires consultation with the owners and the later requires me to become a layout expert.&lt;br /&gt;
&lt;br /&gt;
Benjamin Smedberg suggested taking care of DWARF symbols in breakpad as that will let us use the -fomit-frame-pointer gcc option. Omitting the frame pointer would result in at least a 5% overall speed up because a register will be freed on x86-32.&lt;br /&gt;
&lt;br /&gt;
DWARF is a [https://bugzilla.mozilla.org/showdependencygraph.cgi?id=464750 tree of dependent bugs], though, and Jim Blandy is working on them. Jim is a Linux guy, though, and also has ECMAScript 5 strict mode to take care of whereas I&#039;m strictly focused on performance optimization.&lt;br /&gt;
&lt;br /&gt;
I&#039;ll ask management to see if I can work on DWARF with Jim.&lt;br /&gt;
&lt;br /&gt;
=== September 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Wins ====&lt;br /&gt;
&lt;br /&gt;
Kudos to Masayuki for fixing [https://bugzilla.mozilla.org/show_bug.cgi?id=517549 Bug 517549]. It&#039;s hard to believe but it looks like our Mac Ts [http://graphs.mozilla.org/graph.html#tests=[{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22169%22},{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22173%22},{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22178%22}]&amp;amp;sel=1252833380,1253542320 went down 30%] and it was only 12.3% of my startup. I wonder what happens when [https://bugzilla.mozilla.org/show_bug.cgi?id=517576 Bug 517576] gets fixed, that&#039;s 21% of my startup!&lt;br /&gt;
&lt;br /&gt;
One other thing I&#039;m wondering about... What if all the bottlenecks I find will get fixed by someone else? Damon wants me to write code!!! &lt;br /&gt;
&lt;br /&gt;
=== September 16, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== That mysterious forking ====&lt;br /&gt;
&lt;br /&gt;
Apparently, Firefox forks the first time after a build to rebuild caches, etc. Need to make sure to profile from the 2nd run on. This forking behavior baffled me when I started with DTrace.&lt;br /&gt;
&lt;br /&gt;
==== I&#039;m an idiot ====&lt;br /&gt;
&lt;br /&gt;
I spent a month becoming an expert on DTrace, only to realize that it&#039;s not very useful to get a global picture of the bottlenecks because the overhead of tracing everything is so high! &lt;br /&gt;
&lt;br /&gt;
Shark is a much better tool to get a global picture, specially using &amp;quot;Time profile all states&amp;quot; which allocates time spent blocking to the calling function. I overlooked this initially since I did not zero in on the right thread, the one that has &#039;&#039;start&#039;&#039; and &#039;&#039;XRE_main&#039;&#039; or &#039;&#039;exit&#039;&#039;. Without this it looks like Firefox is spending most of its time waiting on threads and Mach messages.&lt;br /&gt;
&lt;br /&gt;
==== Timing startup ====&lt;br /&gt;
&lt;br /&gt;
A clear picture courtesy of Shark&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	0.0%	92.8%	firefox-bin	start&lt;br /&gt;
	0.0%	92.8%	firefox-bin	 main&lt;br /&gt;
	0.0%	91.6%	XUL	  XRE_main&lt;br /&gt;
	0.0%	40.8%	XUL	   nsAppStartup::CreateHiddenWindow()&lt;br /&gt;
	0.0%	34.7%	XUL	   ScopedXPCOMStartup::Initialize()&lt;br /&gt;
	0.0%	6.4%	XUL	   ScopedXPCOMStartup::~ScopedXPCOMStartup()&lt;br /&gt;
	0.0%	3.4%	XUL	   ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport*)&lt;br /&gt;
	0.0%	2.4%	XUL	   nsXPTCStubBase::Stub3()&lt;br /&gt;
	0.0%	0.8%	XUL	   nsAppStartupNotifier::Observe(nsISupports*, char const*, unsigned short const*)&lt;br /&gt;
	0.0%	0.8%	HIToolbox	   GetCurrentEventKeyModifiers&lt;br /&gt;
	0.0%	0.6%	XUL	   nsXREDirProvider::DoStartup()&lt;br /&gt;
	0.0%	0.5%	XUL	   RemoveComponentRegistries(nsIFile*, nsIFile*, int)&lt;br /&gt;
	0.0%	0.4%	XUL	   NS_NewToolkitProfileService(nsIToolkitProfileService**)&lt;br /&gt;
	0.0%	0.3%	XUL	   nsToolkitProfile::Lock(nsIProfileUnlocker**, nsIProfileLock**)&lt;br /&gt;
	0.0%	0.1%	XUL	   WriteVersion(nsIFile*, nsCString const&amp;amp;, nsCString const&amp;amp;, nsIFile*, nsIFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   nsINIParser_internal::Init(nsILocalFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   LaunchChildMac&lt;br /&gt;
	0.0%	0.4%	XUL	  XRE_GetBinaryPath&lt;br /&gt;
	0.3%	0.4%	XUL	  XRE_CreateAppData&lt;br /&gt;
	0.4%	0.4%	XUL	  NS_LogInit_P&lt;br /&gt;
	0.0%	6.2%	dyld	_dyld_start&lt;br /&gt;
	1.0%	1.0%	libSystem.B.dylib	_exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Breaking startup into smaller chunks ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: I really think that &amp;quot;Ts&amp;quot; is still much too large of a chunk to make meaningful improvements on&lt;br /&gt;
bsmedberg:joelr: in order to make meaninful discoveries, I think you have to break startup down into pieces and then maybe improve each piece&lt;br /&gt;
joelr:bsmedberg: i&#039;m listening&lt;br /&gt;
bsmedberg:well, you&#039;ve got various stuff that happens up until you start the event loop&lt;br /&gt;
bsmedberg:breaking XRE_main into phases up until nsAppStartup::Run would be interesting&lt;br /&gt;
bsmedberg:I still haven&#039;t seen a graph or anything of how we break down&lt;br /&gt;
bsmedberg:joelr: I think stepping through in a debugger might give you a better sense of what&#039;s going on (up until Run()) than profiles would&lt;br /&gt;
bsmedberg:even if you broke things up into &amp;quot;from main() to the beginning of event loop&amp;quot; and &amp;quot;after the event loop starts&amp;quot; that would be more interesting&lt;br /&gt;
bsmedberg:joelr: and then within the first chunk, timing NS_InitXPCOM, the extension manager bits, chromereg startup&lt;br /&gt;
bsmedberg:joelr: I think this intersects with some of the startup-timeline stuff taras was doing&lt;br /&gt;
joelr:bsmedberg: what are the functions for &amp;quot;extension manager bits&amp;quot; and &amp;quot;chromereg startup&amp;quot;?&lt;br /&gt;
bsmedberg:joelr: basically from http://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#2607 to #3453&lt;br /&gt;
joelr:bsmedberg: thanks for the suggestion, i&#039;ll do that&lt;br /&gt;
bsmedberg:joelr: #3382 to #3408 or so&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XUL reflow ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:joelr: so I&#039;m still wondering about some of the reflow stuff&lt;br /&gt;
bz:joelr: I know it&#039;s hard, but that&#039;s why no one&#039;s really dived into it yet&lt;br /&gt;
bz:joelr: and I&#039;d love to know whether we do in fact end up looping significantly in sprocket layout during startup, for example&lt;br /&gt;
joelr:bz: i&#039;m still wondering about reflow myself but i&#039;m not quite ready to tackle it yet&lt;br /&gt;
joelr:bz: don&#039;t know enough&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Shark tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== Expanding the call tree === &lt;br /&gt;
&lt;br /&gt;
Alt-Click does it.&lt;br /&gt;
&lt;br /&gt;
=== CHUD signposts on Snow Leopard ===&lt;br /&gt;
&lt;br /&gt;
There are no CHUD header files on Snow Leopard. If you&#039;re only interest is in emitting signposts, the easiest thing for you to do is switch to the syscall method instead.  That&#039;ll also mean you won&#039;t have to link against the CHUD framework. The full details are in the Shark User Guide, but in brief:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int err = syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, &amp;lt;your code number&amp;gt;) | &amp;lt;type&amp;gt;, arg1, arg2, arg3, arg4);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Types are DBG_FUNC_START, DBG_FUNC_END and DBG_FUNC_NONE (for point signposts).&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to include &amp;lt;sys/kdebug.h&amp;gt; and &amp;lt;sys/syscall.h&amp;gt; for the necessary macros and function.&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=170188</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=170188"/>
		<updated>2009-09-23T13:06:17Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 23, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== A shiny new world ==== &lt;br /&gt;
&lt;br /&gt;
Damon thinks I should help Josh with the 64-bit port. 64-bit Trace Monkey gives us a [http://www.bailopan.net/blog/?p=595 20% improvement in speed] which beats the 5% DWARF improvement from -fomit-frame-pointer. I didn&#039;t know it was my birthday!&lt;br /&gt;
&lt;br /&gt;
I&#039;m leaving the 32-bit world behind. 64 bits here I come!&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 22, 2009 ===&lt;br /&gt;
&lt;br /&gt;
I have two bottlenecks on my plate, [https://bugzilla.mozilla.org/show_bug.cgi?id=517045 Bug 517045] and [https://bugzilla.mozilla.org/show_bug.cgi?id=517576 Bug 517576]. Both of them may not be possible to speed up significantly, not without a large research effort. The former requires consultation with the owners and the later requires me to become a layout expert.&lt;br /&gt;
&lt;br /&gt;
Benjamin Smedberg suggested taking care of DWARF symbols in breakpad as that will let us use the -fomit-frame-pointer gcc option. Omitting the frame pointer would result in at least a 5% overall speed up because a register will be freed on x86-32.&lt;br /&gt;
&lt;br /&gt;
DWARF is a [https://bugzilla.mozilla.org/showdependencygraph.cgi?id=464750 tree of dependent bugs], though, and Jim Blandy is working on them. Jim is a Linux guy, though, and also has ECMAScript 5 strict mode to take care of whereas I&#039;m strictly focused on performance optimization.&lt;br /&gt;
&lt;br /&gt;
I&#039;ll ask management to see if I can work on DWARF with Jim.&lt;br /&gt;
&lt;br /&gt;
=== September 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Wins ====&lt;br /&gt;
&lt;br /&gt;
Kudos to Masayuki for fixing [https://bugzilla.mozilla.org/show_bug.cgi?id=517549 Bug 517549]. It&#039;s hard to believe but it looks like our Mac Ts [http://graphs.mozilla.org/graph.html#tests=[{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22169%22},{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22173%22},{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22178%22}]&amp;amp;sel=1252833380,1253542320 went down 30%] and it was only 12.3% of my startup. I wonder what happens when [https://bugzilla.mozilla.org/show_bug.cgi?id=517576 Bug 517576] gets fixed, that&#039;s 21% of my startup!&lt;br /&gt;
&lt;br /&gt;
One other thing I&#039;m wondering about... What if all the bottlenecks I find will get fixed by someone else? Damon wants me to write code!!! &lt;br /&gt;
&lt;br /&gt;
=== September 16, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== That mysterious forking ====&lt;br /&gt;
&lt;br /&gt;
Apparently, Firefox forks the first time after a build to rebuild caches, etc. Need to make sure to profile from the 2nd run on. This forking behavior baffled me when I started with DTrace.&lt;br /&gt;
&lt;br /&gt;
==== I&#039;m an idiot ====&lt;br /&gt;
&lt;br /&gt;
I spent a month becoming an expert on DTrace, only to realize that it&#039;s not very useful to get a global picture of the bottlenecks because the overhead of tracing everything is so high! &lt;br /&gt;
&lt;br /&gt;
Shark is a much better tool to get a global picture, specially using &amp;quot;Time profile all states&amp;quot; which allocates time spent blocking to the calling function. I overlooked this initially since I did not zero in on the right thread, the one that has &#039;&#039;start&#039;&#039; and &#039;&#039;XRE_main&#039;&#039; or &#039;&#039;exit&#039;&#039;. Without this it looks like Firefox is spending most of its time waiting on threads and Mach messages.&lt;br /&gt;
&lt;br /&gt;
==== Timing startup ====&lt;br /&gt;
&lt;br /&gt;
A clear picture courtesy of Shark&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	0.0%	92.8%	firefox-bin	start&lt;br /&gt;
	0.0%	92.8%	firefox-bin	 main&lt;br /&gt;
	0.0%	91.6%	XUL	  XRE_main&lt;br /&gt;
	0.0%	40.8%	XUL	   nsAppStartup::CreateHiddenWindow()&lt;br /&gt;
	0.0%	34.7%	XUL	   ScopedXPCOMStartup::Initialize()&lt;br /&gt;
	0.0%	6.4%	XUL	   ScopedXPCOMStartup::~ScopedXPCOMStartup()&lt;br /&gt;
	0.0%	3.4%	XUL	   ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport*)&lt;br /&gt;
	0.0%	2.4%	XUL	   nsXPTCStubBase::Stub3()&lt;br /&gt;
	0.0%	0.8%	XUL	   nsAppStartupNotifier::Observe(nsISupports*, char const*, unsigned short const*)&lt;br /&gt;
	0.0%	0.8%	HIToolbox	   GetCurrentEventKeyModifiers&lt;br /&gt;
	0.0%	0.6%	XUL	   nsXREDirProvider::DoStartup()&lt;br /&gt;
	0.0%	0.5%	XUL	   RemoveComponentRegistries(nsIFile*, nsIFile*, int)&lt;br /&gt;
	0.0%	0.4%	XUL	   NS_NewToolkitProfileService(nsIToolkitProfileService**)&lt;br /&gt;
	0.0%	0.3%	XUL	   nsToolkitProfile::Lock(nsIProfileUnlocker**, nsIProfileLock**)&lt;br /&gt;
	0.0%	0.1%	XUL	   WriteVersion(nsIFile*, nsCString const&amp;amp;, nsCString const&amp;amp;, nsIFile*, nsIFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   nsINIParser_internal::Init(nsILocalFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   LaunchChildMac&lt;br /&gt;
	0.0%	0.4%	XUL	  XRE_GetBinaryPath&lt;br /&gt;
	0.3%	0.4%	XUL	  XRE_CreateAppData&lt;br /&gt;
	0.4%	0.4%	XUL	  NS_LogInit_P&lt;br /&gt;
	0.0%	6.2%	dyld	_dyld_start&lt;br /&gt;
	1.0%	1.0%	libSystem.B.dylib	_exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Breaking startup into smaller chunks ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: I really think that &amp;quot;Ts&amp;quot; is still much too large of a chunk to make meaningful improvements on&lt;br /&gt;
bsmedberg:joelr: in order to make meaninful discoveries, I think you have to break startup down into pieces and then maybe improve each piece&lt;br /&gt;
joelr:bsmedberg: i&#039;m listening&lt;br /&gt;
bsmedberg:well, you&#039;ve got various stuff that happens up until you start the event loop&lt;br /&gt;
bsmedberg:breaking XRE_main into phases up until nsAppStartup::Run would be interesting&lt;br /&gt;
bsmedberg:I still haven&#039;t seen a graph or anything of how we break down&lt;br /&gt;
bsmedberg:joelr: I think stepping through in a debugger might give you a better sense of what&#039;s going on (up until Run()) than profiles would&lt;br /&gt;
bsmedberg:even if you broke things up into &amp;quot;from main() to the beginning of event loop&amp;quot; and &amp;quot;after the event loop starts&amp;quot; that would be more interesting&lt;br /&gt;
bsmedberg:joelr: and then within the first chunk, timing NS_InitXPCOM, the extension manager bits, chromereg startup&lt;br /&gt;
bsmedberg:joelr: I think this intersects with some of the startup-timeline stuff taras was doing&lt;br /&gt;
joelr:bsmedberg: what are the functions for &amp;quot;extension manager bits&amp;quot; and &amp;quot;chromereg startup&amp;quot;?&lt;br /&gt;
bsmedberg:joelr: basically from http://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#2607 to #3453&lt;br /&gt;
joelr:bsmedberg: thanks for the suggestion, i&#039;ll do that&lt;br /&gt;
bsmedberg:joelr: #3382 to #3408 or so&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XUL reflow ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:joelr: so I&#039;m still wondering about some of the reflow stuff&lt;br /&gt;
bz:joelr: I know it&#039;s hard, but that&#039;s why no one&#039;s really dived into it yet&lt;br /&gt;
bz:joelr: and I&#039;d love to know whether we do in fact end up looping significantly in sprocket layout during startup, for example&lt;br /&gt;
joelr:bz: i&#039;m still wondering about reflow myself but i&#039;m not quite ready to tackle it yet&lt;br /&gt;
joelr:bz: don&#039;t know enough&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Shark tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== Expanding the call tree === &lt;br /&gt;
&lt;br /&gt;
Alt-Click does it.&lt;br /&gt;
&lt;br /&gt;
=== CHUD signposts on Snow Leopard ===&lt;br /&gt;
&lt;br /&gt;
There are no CHUD header files on Snow Leopard. If you&#039;re only interest is in emitting signposts, the easiest thing for you to do is switch to the syscall method instead.  That&#039;ll also mean you won&#039;t have to link against the CHUD framework. The full details are in the Shark User Guide, but in brief:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int err = syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, &amp;lt;your code number&amp;gt;) | &amp;lt;type&amp;gt;, arg1, arg2, arg3, arg4);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Types are DBG_FUNC_START, DBG_FUNC_END and DBG_FUNC_NONE (for point signposts).&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to include &amp;lt;sys/kdebug.h&amp;gt; and &amp;lt;sys/syscall.h&amp;gt; for the necessary macros and function.&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=169469</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=169469"/>
		<updated>2009-09-21T16:38:15Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Wins ====&lt;br /&gt;
&lt;br /&gt;
Kudos to Masayuki for fixing [https://bugzilla.mozilla.org/show_bug.cgi?id=517549 Bug 517549]. It&#039;s hard to believe but it looks like our Mac Ts [http://graphs.mozilla.org/graph.html#tests=[{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22169%22},{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22173%22},{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22178%22}]&amp;amp;sel=1252833380,1253542320 went down 30%] and it was only 12.3% of my startup. I wonder what happens when [https://bugzilla.mozilla.org/show_bug.cgi?id=517576 Bug 517576] gets fixed, that&#039;s 21% of my startup!&lt;br /&gt;
&lt;br /&gt;
One other thing I&#039;m wondering about... What if all the bottlenecks I find will get fixed by someone else? Damon wants me to write code!!! &lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 16, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== That mysterious forking ====&lt;br /&gt;
&lt;br /&gt;
Apparently, Firefox forks the first time after a build to rebuild caches, etc. Need to make sure to profile from the 2nd run on. This forking behavior baffled me when I started with DTrace.&lt;br /&gt;
&lt;br /&gt;
==== I&#039;m an idiot ====&lt;br /&gt;
&lt;br /&gt;
I spent a month becoming an expert on DTrace, only to realize that it&#039;s not very useful to get a global picture of the bottlenecks because the overhead of tracing everything is so high! &lt;br /&gt;
&lt;br /&gt;
Shark is a much better tool to get a global picture, specially using &amp;quot;Time profile all states&amp;quot; which allocates time spent blocking to the calling function. I overlooked this initially since I did not zero in on the right thread, the one that has &#039;&#039;start&#039;&#039; and &#039;&#039;XRE_main&#039;&#039; or &#039;&#039;exit&#039;&#039;. Without this it looks like Firefox is spending most of its time waiting on threads and Mach messages.&lt;br /&gt;
&lt;br /&gt;
==== Timing startup ====&lt;br /&gt;
&lt;br /&gt;
A clear picture courtesy of Shark&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	0.0%	92.8%	firefox-bin	start&lt;br /&gt;
	0.0%	92.8%	firefox-bin	 main&lt;br /&gt;
	0.0%	91.6%	XUL	  XRE_main&lt;br /&gt;
	0.0%	40.8%	XUL	   nsAppStartup::CreateHiddenWindow()&lt;br /&gt;
	0.0%	34.7%	XUL	   ScopedXPCOMStartup::Initialize()&lt;br /&gt;
	0.0%	6.4%	XUL	   ScopedXPCOMStartup::~ScopedXPCOMStartup()&lt;br /&gt;
	0.0%	3.4%	XUL	   ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport*)&lt;br /&gt;
	0.0%	2.4%	XUL	   nsXPTCStubBase::Stub3()&lt;br /&gt;
	0.0%	0.8%	XUL	   nsAppStartupNotifier::Observe(nsISupports*, char const*, unsigned short const*)&lt;br /&gt;
	0.0%	0.8%	HIToolbox	   GetCurrentEventKeyModifiers&lt;br /&gt;
	0.0%	0.6%	XUL	   nsXREDirProvider::DoStartup()&lt;br /&gt;
	0.0%	0.5%	XUL	   RemoveComponentRegistries(nsIFile*, nsIFile*, int)&lt;br /&gt;
	0.0%	0.4%	XUL	   NS_NewToolkitProfileService(nsIToolkitProfileService**)&lt;br /&gt;
	0.0%	0.3%	XUL	   nsToolkitProfile::Lock(nsIProfileUnlocker**, nsIProfileLock**)&lt;br /&gt;
	0.0%	0.1%	XUL	   WriteVersion(nsIFile*, nsCString const&amp;amp;, nsCString const&amp;amp;, nsIFile*, nsIFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   nsINIParser_internal::Init(nsILocalFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   LaunchChildMac&lt;br /&gt;
	0.0%	0.4%	XUL	  XRE_GetBinaryPath&lt;br /&gt;
	0.3%	0.4%	XUL	  XRE_CreateAppData&lt;br /&gt;
	0.4%	0.4%	XUL	  NS_LogInit_P&lt;br /&gt;
	0.0%	6.2%	dyld	_dyld_start&lt;br /&gt;
	1.0%	1.0%	libSystem.B.dylib	_exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Breaking startup into smaller chunks ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: I really think that &amp;quot;Ts&amp;quot; is still much too large of a chunk to make meaningful improvements on&lt;br /&gt;
bsmedberg:joelr: in order to make meaninful discoveries, I think you have to break startup down into pieces and then maybe improve each piece&lt;br /&gt;
joelr:bsmedberg: i&#039;m listening&lt;br /&gt;
bsmedberg:well, you&#039;ve got various stuff that happens up until you start the event loop&lt;br /&gt;
bsmedberg:breaking XRE_main into phases up until nsAppStartup::Run would be interesting&lt;br /&gt;
bsmedberg:I still haven&#039;t seen a graph or anything of how we break down&lt;br /&gt;
bsmedberg:joelr: I think stepping through in a debugger might give you a better sense of what&#039;s going on (up until Run()) than profiles would&lt;br /&gt;
bsmedberg:even if you broke things up into &amp;quot;from main() to the beginning of event loop&amp;quot; and &amp;quot;after the event loop starts&amp;quot; that would be more interesting&lt;br /&gt;
bsmedberg:joelr: and then within the first chunk, timing NS_InitXPCOM, the extension manager bits, chromereg startup&lt;br /&gt;
bsmedberg:joelr: I think this intersects with some of the startup-timeline stuff taras was doing&lt;br /&gt;
joelr:bsmedberg: what are the functions for &amp;quot;extension manager bits&amp;quot; and &amp;quot;chromereg startup&amp;quot;?&lt;br /&gt;
bsmedberg:joelr: basically from http://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#2607 to #3453&lt;br /&gt;
joelr:bsmedberg: thanks for the suggestion, i&#039;ll do that&lt;br /&gt;
bsmedberg:joelr: #3382 to #3408 or so&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XUL reflow ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:joelr: so I&#039;m still wondering about some of the reflow stuff&lt;br /&gt;
bz:joelr: I know it&#039;s hard, but that&#039;s why no one&#039;s really dived into it yet&lt;br /&gt;
bz:joelr: and I&#039;d love to know whether we do in fact end up looping significantly in sprocket layout during startup, for example&lt;br /&gt;
joelr:bz: i&#039;m still wondering about reflow myself but i&#039;m not quite ready to tackle it yet&lt;br /&gt;
joelr:bz: don&#039;t know enough&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Shark tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== Expanding the call tree === &lt;br /&gt;
&lt;br /&gt;
Alt-Click does it.&lt;br /&gt;
&lt;br /&gt;
=== CHUD signposts on Snow Leopard ===&lt;br /&gt;
&lt;br /&gt;
There are no CHUD header files on Snow Leopard. If you&#039;re only interest is in emitting signposts, the easiest thing for you to do is switch to the syscall method instead.  That&#039;ll also mean you won&#039;t have to link against the CHUD framework. The full details are in the Shark User Guide, but in brief:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int err = syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, &amp;lt;your code number&amp;gt;) | &amp;lt;type&amp;gt;, arg1, arg2, arg3, arg4);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Types are DBG_FUNC_START, DBG_FUNC_END and DBG_FUNC_NONE (for point signposts).&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to include &amp;lt;sys/kdebug.h&amp;gt; and &amp;lt;sys/syscall.h&amp;gt; for the necessary macros and function.&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=169468</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=169468"/>
		<updated>2009-09-21T16:37:11Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Wins ====&lt;br /&gt;
&lt;br /&gt;
Kudos to Masayuki for fixing [https://bugzilla.mozilla.org/show_bug.cgi?id=517549 Bug 517549]. It&#039;s hard to believe but it looks like our Mac Ts [http://graphs.mozilla.org/graph.html#tests=[{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22169%22},{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22173%22},{%22test%22:%2216%22,%22branch%22:%221%22,%22machine%22:%22178%22}]&amp;amp;sel=1252833380,1253542320 went down 30%] and it was only 12.3% of my startup. I wonder what happens when [https://bugzilla.mozilla.org/show_bug.cgi?id=517576 Bug 517576] gets fixed, that&#039;s 21% of my startup!&lt;br /&gt;
&lt;br /&gt;
One other thing I&#039;m wondering about... What if all the bottlenecks I find will get fixed by someone else? Damon wants me to write code!!! &lt;br /&gt;
&lt;br /&gt;
=== September 16, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== That mysterious forking ====&lt;br /&gt;
&lt;br /&gt;
Apparently, Firefox forks the first time after a build to rebuild caches, etc. Need to make sure to profile from the 2nd run on. This forking behavior baffled me when I started with DTrace.&lt;br /&gt;
&lt;br /&gt;
==== I&#039;m an idiot ====&lt;br /&gt;
&lt;br /&gt;
I spent a month becoming an expert on DTrace, only to realize that it&#039;s not very useful to get a global picture of the bottlenecks because the overhead of tracing everything is so high! &lt;br /&gt;
&lt;br /&gt;
Shark is a much better tool to get a global picture, specially using &amp;quot;Time profile all states&amp;quot; which allocates time spent blocking to the calling function. I overlooked this initially since I did not zero in on the right thread, the one that has &#039;&#039;start&#039;&#039; and &#039;&#039;XRE_main&#039;&#039; or &#039;&#039;exit&#039;&#039;. Without this it looks like Firefox is spending most of its time waiting on threads and Mach messages.&lt;br /&gt;
&lt;br /&gt;
==== Timing startup ====&lt;br /&gt;
&lt;br /&gt;
A clear picture courtesy of Shark&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	0.0%	92.8%	firefox-bin	start&lt;br /&gt;
	0.0%	92.8%	firefox-bin	 main&lt;br /&gt;
	0.0%	91.6%	XUL	  XRE_main&lt;br /&gt;
	0.0%	40.8%	XUL	   nsAppStartup::CreateHiddenWindow()&lt;br /&gt;
	0.0%	34.7%	XUL	   ScopedXPCOMStartup::Initialize()&lt;br /&gt;
	0.0%	6.4%	XUL	   ScopedXPCOMStartup::~ScopedXPCOMStartup()&lt;br /&gt;
	0.0%	3.4%	XUL	   ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport*)&lt;br /&gt;
	0.0%	2.4%	XUL	   nsXPTCStubBase::Stub3()&lt;br /&gt;
	0.0%	0.8%	XUL	   nsAppStartupNotifier::Observe(nsISupports*, char const*, unsigned short const*)&lt;br /&gt;
	0.0%	0.8%	HIToolbox	   GetCurrentEventKeyModifiers&lt;br /&gt;
	0.0%	0.6%	XUL	   nsXREDirProvider::DoStartup()&lt;br /&gt;
	0.0%	0.5%	XUL	   RemoveComponentRegistries(nsIFile*, nsIFile*, int)&lt;br /&gt;
	0.0%	0.4%	XUL	   NS_NewToolkitProfileService(nsIToolkitProfileService**)&lt;br /&gt;
	0.0%	0.3%	XUL	   nsToolkitProfile::Lock(nsIProfileUnlocker**, nsIProfileLock**)&lt;br /&gt;
	0.0%	0.1%	XUL	   WriteVersion(nsIFile*, nsCString const&amp;amp;, nsCString const&amp;amp;, nsIFile*, nsIFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   nsINIParser_internal::Init(nsILocalFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   LaunchChildMac&lt;br /&gt;
	0.0%	0.4%	XUL	  XRE_GetBinaryPath&lt;br /&gt;
	0.3%	0.4%	XUL	  XRE_CreateAppData&lt;br /&gt;
	0.4%	0.4%	XUL	  NS_LogInit_P&lt;br /&gt;
	0.0%	6.2%	dyld	_dyld_start&lt;br /&gt;
	1.0%	1.0%	libSystem.B.dylib	_exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Breaking startup into smaller chunks ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: I really think that &amp;quot;Ts&amp;quot; is still much too large of a chunk to make meaningful improvements on&lt;br /&gt;
bsmedberg:joelr: in order to make meaninful discoveries, I think you have to break startup down into pieces and then maybe improve each piece&lt;br /&gt;
joelr:bsmedberg: i&#039;m listening&lt;br /&gt;
bsmedberg:well, you&#039;ve got various stuff that happens up until you start the event loop&lt;br /&gt;
bsmedberg:breaking XRE_main into phases up until nsAppStartup::Run would be interesting&lt;br /&gt;
bsmedberg:I still haven&#039;t seen a graph or anything of how we break down&lt;br /&gt;
bsmedberg:joelr: I think stepping through in a debugger might give you a better sense of what&#039;s going on (up until Run()) than profiles would&lt;br /&gt;
bsmedberg:even if you broke things up into &amp;quot;from main() to the beginning of event loop&amp;quot; and &amp;quot;after the event loop starts&amp;quot; that would be more interesting&lt;br /&gt;
bsmedberg:joelr: and then within the first chunk, timing NS_InitXPCOM, the extension manager bits, chromereg startup&lt;br /&gt;
bsmedberg:joelr: I think this intersects with some of the startup-timeline stuff taras was doing&lt;br /&gt;
joelr:bsmedberg: what are the functions for &amp;quot;extension manager bits&amp;quot; and &amp;quot;chromereg startup&amp;quot;?&lt;br /&gt;
bsmedberg:joelr: basically from http://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#2607 to #3453&lt;br /&gt;
joelr:bsmedberg: thanks for the suggestion, i&#039;ll do that&lt;br /&gt;
bsmedberg:joelr: #3382 to #3408 or so&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XUL reflow ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:joelr: so I&#039;m still wondering about some of the reflow stuff&lt;br /&gt;
bz:joelr: I know it&#039;s hard, but that&#039;s why no one&#039;s really dived into it yet&lt;br /&gt;
bz:joelr: and I&#039;d love to know whether we do in fact end up looping significantly in sprocket layout during startup, for example&lt;br /&gt;
joelr:bz: i&#039;m still wondering about reflow myself but i&#039;m not quite ready to tackle it yet&lt;br /&gt;
joelr:bz: don&#039;t know enough&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Shark tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== Expanding the call tree === &lt;br /&gt;
&lt;br /&gt;
Alt-Click does it.&lt;br /&gt;
&lt;br /&gt;
=== CHUD signposts on Snow Leopard ===&lt;br /&gt;
&lt;br /&gt;
There are no CHUD header files on Snow Leopard. If you&#039;re only interest is in emitting signposts, the easiest thing for you to do is switch to the syscall method instead.  That&#039;ll also mean you won&#039;t have to link against the CHUD framework. The full details are in the Shark User Guide, but in brief:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int err = syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, &amp;lt;your code number&amp;gt;) | &amp;lt;type&amp;gt;, arg1, arg2, arg3, arg4);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Types are DBG_FUNC_START, DBG_FUNC_END and DBG_FUNC_NONE (for point signposts).&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to include &amp;lt;sys/kdebug.h&amp;gt; and &amp;lt;sys/syscall.h&amp;gt; for the necessary macros and function.&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=169217</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=169217"/>
		<updated>2009-09-18T15:46:20Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Shark tips and tricks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 16, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== That mysterious forking ====&lt;br /&gt;
&lt;br /&gt;
Apparently, Firefox forks the first time after a build to rebuild caches, etc. Need to make sure to profile from the 2nd run on. This forking behavior baffled me when I started with DTrace.&lt;br /&gt;
&lt;br /&gt;
==== I&#039;m an idiot ====&lt;br /&gt;
&lt;br /&gt;
I spent a month becoming an expert on DTrace, only to realize that it&#039;s not very useful to get a global picture of the bottlenecks because the overhead of tracing everything is so high! &lt;br /&gt;
&lt;br /&gt;
Shark is a much better tool to get a global picture, specially using &amp;quot;Time profile all states&amp;quot; which allocates time spent blocking to the calling function. I overlooked this initially since I did not zero in on the right thread, the one that has &#039;&#039;start&#039;&#039; and &#039;&#039;XRE_main&#039;&#039; or &#039;&#039;exit&#039;&#039;. Without this it looks like Firefox is spending most of its time waiting on threads and Mach messages.&lt;br /&gt;
&lt;br /&gt;
==== Timing startup ====&lt;br /&gt;
&lt;br /&gt;
A clear picture courtesy of Shark&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	0.0%	92.8%	firefox-bin	start&lt;br /&gt;
	0.0%	92.8%	firefox-bin	 main&lt;br /&gt;
	0.0%	91.6%	XUL	  XRE_main&lt;br /&gt;
	0.0%	40.8%	XUL	   nsAppStartup::CreateHiddenWindow()&lt;br /&gt;
	0.0%	34.7%	XUL	   ScopedXPCOMStartup::Initialize()&lt;br /&gt;
	0.0%	6.4%	XUL	   ScopedXPCOMStartup::~ScopedXPCOMStartup()&lt;br /&gt;
	0.0%	3.4%	XUL	   ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport*)&lt;br /&gt;
	0.0%	2.4%	XUL	   nsXPTCStubBase::Stub3()&lt;br /&gt;
	0.0%	0.8%	XUL	   nsAppStartupNotifier::Observe(nsISupports*, char const*, unsigned short const*)&lt;br /&gt;
	0.0%	0.8%	HIToolbox	   GetCurrentEventKeyModifiers&lt;br /&gt;
	0.0%	0.6%	XUL	   nsXREDirProvider::DoStartup()&lt;br /&gt;
	0.0%	0.5%	XUL	   RemoveComponentRegistries(nsIFile*, nsIFile*, int)&lt;br /&gt;
	0.0%	0.4%	XUL	   NS_NewToolkitProfileService(nsIToolkitProfileService**)&lt;br /&gt;
	0.0%	0.3%	XUL	   nsToolkitProfile::Lock(nsIProfileUnlocker**, nsIProfileLock**)&lt;br /&gt;
	0.0%	0.1%	XUL	   WriteVersion(nsIFile*, nsCString const&amp;amp;, nsCString const&amp;amp;, nsIFile*, nsIFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   nsINIParser_internal::Init(nsILocalFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   LaunchChildMac&lt;br /&gt;
	0.0%	0.4%	XUL	  XRE_GetBinaryPath&lt;br /&gt;
	0.3%	0.4%	XUL	  XRE_CreateAppData&lt;br /&gt;
	0.4%	0.4%	XUL	  NS_LogInit_P&lt;br /&gt;
	0.0%	6.2%	dyld	_dyld_start&lt;br /&gt;
	1.0%	1.0%	libSystem.B.dylib	_exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Breaking startup into smaller chunks ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: I really think that &amp;quot;Ts&amp;quot; is still much too large of a chunk to make meaningful improvements on&lt;br /&gt;
bsmedberg:joelr: in order to make meaninful discoveries, I think you have to break startup down into pieces and then maybe improve each piece&lt;br /&gt;
joelr:bsmedberg: i&#039;m listening&lt;br /&gt;
bsmedberg:well, you&#039;ve got various stuff that happens up until you start the event loop&lt;br /&gt;
bsmedberg:breaking XRE_main into phases up until nsAppStartup::Run would be interesting&lt;br /&gt;
bsmedberg:I still haven&#039;t seen a graph or anything of how we break down&lt;br /&gt;
bsmedberg:joelr: I think stepping through in a debugger might give you a better sense of what&#039;s going on (up until Run()) than profiles would&lt;br /&gt;
bsmedberg:even if you broke things up into &amp;quot;from main() to the beginning of event loop&amp;quot; and &amp;quot;after the event loop starts&amp;quot; that would be more interesting&lt;br /&gt;
bsmedberg:joelr: and then within the first chunk, timing NS_InitXPCOM, the extension manager bits, chromereg startup&lt;br /&gt;
bsmedberg:joelr: I think this intersects with some of the startup-timeline stuff taras was doing&lt;br /&gt;
joelr:bsmedberg: what are the functions for &amp;quot;extension manager bits&amp;quot; and &amp;quot;chromereg startup&amp;quot;?&lt;br /&gt;
bsmedberg:joelr: basically from http://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#2607 to #3453&lt;br /&gt;
joelr:bsmedberg: thanks for the suggestion, i&#039;ll do that&lt;br /&gt;
bsmedberg:joelr: #3382 to #3408 or so&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XUL reflow ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:joelr: so I&#039;m still wondering about some of the reflow stuff&lt;br /&gt;
bz:joelr: I know it&#039;s hard, but that&#039;s why no one&#039;s really dived into it yet&lt;br /&gt;
bz:joelr: and I&#039;d love to know whether we do in fact end up looping significantly in sprocket layout during startup, for example&lt;br /&gt;
joelr:bz: i&#039;m still wondering about reflow myself but i&#039;m not quite ready to tackle it yet&lt;br /&gt;
joelr:bz: don&#039;t know enough&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Shark tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== Expanding the call tree === &lt;br /&gt;
&lt;br /&gt;
Alt-Click does it.&lt;br /&gt;
&lt;br /&gt;
=== CHUD signposts on Snow Leopard ===&lt;br /&gt;
&lt;br /&gt;
There are no CHUD header files on Snow Leopard. If you&#039;re only interest is in emitting signposts, the easiest thing for you to do is switch to the syscall method instead.  That&#039;ll also mean you won&#039;t have to link against the CHUD framework. The full details are in the Shark User Guide, but in brief:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int err = syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, &amp;lt;your code number&amp;gt;) | &amp;lt;type&amp;gt;, arg1, arg2, arg3, arg4);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Types are DBG_FUNC_START, DBG_FUNC_END and DBG_FUNC_NONE (for point signposts).&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to include &amp;lt;sys/kdebug.h&amp;gt; and &amp;lt;sys/syscall.h&amp;gt; for the necessary macros and function.&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=169216</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=169216"/>
		<updated>2009-09-18T15:43:51Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 16, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== That mysterious forking ====&lt;br /&gt;
&lt;br /&gt;
Apparently, Firefox forks the first time after a build to rebuild caches, etc. Need to make sure to profile from the 2nd run on. This forking behavior baffled me when I started with DTrace.&lt;br /&gt;
&lt;br /&gt;
==== I&#039;m an idiot ====&lt;br /&gt;
&lt;br /&gt;
I spent a month becoming an expert on DTrace, only to realize that it&#039;s not very useful to get a global picture of the bottlenecks because the overhead of tracing everything is so high! &lt;br /&gt;
&lt;br /&gt;
Shark is a much better tool to get a global picture, specially using &amp;quot;Time profile all states&amp;quot; which allocates time spent blocking to the calling function. I overlooked this initially since I did not zero in on the right thread, the one that has &#039;&#039;start&#039;&#039; and &#039;&#039;XRE_main&#039;&#039; or &#039;&#039;exit&#039;&#039;. Without this it looks like Firefox is spending most of its time waiting on threads and Mach messages.&lt;br /&gt;
&lt;br /&gt;
==== Timing startup ====&lt;br /&gt;
&lt;br /&gt;
A clear picture courtesy of Shark&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	0.0%	92.8%	firefox-bin	start&lt;br /&gt;
	0.0%	92.8%	firefox-bin	 main&lt;br /&gt;
	0.0%	91.6%	XUL	  XRE_main&lt;br /&gt;
	0.0%	40.8%	XUL	   nsAppStartup::CreateHiddenWindow()&lt;br /&gt;
	0.0%	34.7%	XUL	   ScopedXPCOMStartup::Initialize()&lt;br /&gt;
	0.0%	6.4%	XUL	   ScopedXPCOMStartup::~ScopedXPCOMStartup()&lt;br /&gt;
	0.0%	3.4%	XUL	   ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport*)&lt;br /&gt;
	0.0%	2.4%	XUL	   nsXPTCStubBase::Stub3()&lt;br /&gt;
	0.0%	0.8%	XUL	   nsAppStartupNotifier::Observe(nsISupports*, char const*, unsigned short const*)&lt;br /&gt;
	0.0%	0.8%	HIToolbox	   GetCurrentEventKeyModifiers&lt;br /&gt;
	0.0%	0.6%	XUL	   nsXREDirProvider::DoStartup()&lt;br /&gt;
	0.0%	0.5%	XUL	   RemoveComponentRegistries(nsIFile*, nsIFile*, int)&lt;br /&gt;
	0.0%	0.4%	XUL	   NS_NewToolkitProfileService(nsIToolkitProfileService**)&lt;br /&gt;
	0.0%	0.3%	XUL	   nsToolkitProfile::Lock(nsIProfileUnlocker**, nsIProfileLock**)&lt;br /&gt;
	0.0%	0.1%	XUL	   WriteVersion(nsIFile*, nsCString const&amp;amp;, nsCString const&amp;amp;, nsIFile*, nsIFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   nsINIParser_internal::Init(nsILocalFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   LaunchChildMac&lt;br /&gt;
	0.0%	0.4%	XUL	  XRE_GetBinaryPath&lt;br /&gt;
	0.3%	0.4%	XUL	  XRE_CreateAppData&lt;br /&gt;
	0.4%	0.4%	XUL	  NS_LogInit_P&lt;br /&gt;
	0.0%	6.2%	dyld	_dyld_start&lt;br /&gt;
	1.0%	1.0%	libSystem.B.dylib	_exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Breaking startup into smaller chunks ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: I really think that &amp;quot;Ts&amp;quot; is still much too large of a chunk to make meaningful improvements on&lt;br /&gt;
bsmedberg:joelr: in order to make meaninful discoveries, I think you have to break startup down into pieces and then maybe improve each piece&lt;br /&gt;
joelr:bsmedberg: i&#039;m listening&lt;br /&gt;
bsmedberg:well, you&#039;ve got various stuff that happens up until you start the event loop&lt;br /&gt;
bsmedberg:breaking XRE_main into phases up until nsAppStartup::Run would be interesting&lt;br /&gt;
bsmedberg:I still haven&#039;t seen a graph or anything of how we break down&lt;br /&gt;
bsmedberg:joelr: I think stepping through in a debugger might give you a better sense of what&#039;s going on (up until Run()) than profiles would&lt;br /&gt;
bsmedberg:even if you broke things up into &amp;quot;from main() to the beginning of event loop&amp;quot; and &amp;quot;after the event loop starts&amp;quot; that would be more interesting&lt;br /&gt;
bsmedberg:joelr: and then within the first chunk, timing NS_InitXPCOM, the extension manager bits, chromereg startup&lt;br /&gt;
bsmedberg:joelr: I think this intersects with some of the startup-timeline stuff taras was doing&lt;br /&gt;
joelr:bsmedberg: what are the functions for &amp;quot;extension manager bits&amp;quot; and &amp;quot;chromereg startup&amp;quot;?&lt;br /&gt;
bsmedberg:joelr: basically from http://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#2607 to #3453&lt;br /&gt;
joelr:bsmedberg: thanks for the suggestion, i&#039;ll do that&lt;br /&gt;
bsmedberg:joelr: #3382 to #3408 or so&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XUL reflow ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:joelr: so I&#039;m still wondering about some of the reflow stuff&lt;br /&gt;
bz:joelr: I know it&#039;s hard, but that&#039;s why no one&#039;s really dived into it yet&lt;br /&gt;
bz:joelr: and I&#039;d love to know whether we do in fact end up looping significantly in sprocket layout during startup, for example&lt;br /&gt;
joelr:bz: i&#039;m still wondering about reflow myself but i&#039;m not quite ready to tackle it yet&lt;br /&gt;
joelr:bz: don&#039;t know enough&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Shark tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== CHUD signposts on Snow Leopard ===&lt;br /&gt;
&lt;br /&gt;
There are no CHUD header files on Snow Leopard. If you&#039;re only interest is in emitting signposts, the easiest thing for you to do is switch to the syscall method instead.  That&#039;ll also mean you won&#039;t have to link against the CHUD framework. The full details are in the Shark User Guide, but in brief:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int err = syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, &amp;lt;your code number&amp;gt;) | &amp;lt;type&amp;gt;, arg1, arg2, arg3, arg4);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Types are DBG_FUNC_START, DBG_FUNC_END and DBG_FUNC_NONE (for point signposts).&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to include &amp;lt;sys/kdebug.h&amp;gt; and &amp;lt;sys/syscall.h&amp;gt; for the necessary macros and function.&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168814</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168814"/>
		<updated>2009-09-16T19:32:56Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* September 16, 2009 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 16, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== That mysterious forking ====&lt;br /&gt;
&lt;br /&gt;
Apparently, Firefox forks the first time after a build to rebuild caches, etc. Need to make sure to profile from the 2nd run on. This forking behavior baffled me when I started with DTrace.&lt;br /&gt;
&lt;br /&gt;
==== I&#039;m an idiot ====&lt;br /&gt;
&lt;br /&gt;
I spent a month becoming an expert on DTrace, only to realize that it&#039;s not very useful to get a global picture of the bottlenecks because the overhead of tracing everything is so high! &lt;br /&gt;
&lt;br /&gt;
Shark is a much better tool to get a global picture, specially using &amp;quot;Time profile all states&amp;quot; which allocates time spent blocking to the calling function. I overlooked this initially since I did not zero in on the right thread, the one that has &#039;&#039;start&#039;&#039; and &#039;&#039;XRE_main&#039;&#039; or &#039;&#039;exit&#039;&#039;. Without this it looks like Firefox is spending most of its time waiting on threads and Mach messages.&lt;br /&gt;
&lt;br /&gt;
==== Timing startup ====&lt;br /&gt;
&lt;br /&gt;
A clear picture courtesy of Shark&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	0.0%	92.8%	firefox-bin	start&lt;br /&gt;
	0.0%	92.8%	firefox-bin	 main&lt;br /&gt;
	0.0%	91.6%	XUL	  XRE_main&lt;br /&gt;
	0.0%	40.8%	XUL	   nsAppStartup::CreateHiddenWindow()&lt;br /&gt;
	0.0%	34.7%	XUL	   ScopedXPCOMStartup::Initialize()&lt;br /&gt;
	0.0%	6.4%	XUL	   ScopedXPCOMStartup::~ScopedXPCOMStartup()&lt;br /&gt;
	0.0%	3.4%	XUL	   ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport*)&lt;br /&gt;
	0.0%	2.4%	XUL	   nsXPTCStubBase::Stub3()&lt;br /&gt;
	0.0%	0.8%	XUL	   nsAppStartupNotifier::Observe(nsISupports*, char const*, unsigned short const*)&lt;br /&gt;
	0.0%	0.8%	HIToolbox	   GetCurrentEventKeyModifiers&lt;br /&gt;
	0.0%	0.6%	XUL	   nsXREDirProvider::DoStartup()&lt;br /&gt;
	0.0%	0.5%	XUL	   RemoveComponentRegistries(nsIFile*, nsIFile*, int)&lt;br /&gt;
	0.0%	0.4%	XUL	   NS_NewToolkitProfileService(nsIToolkitProfileService**)&lt;br /&gt;
	0.0%	0.3%	XUL	   nsToolkitProfile::Lock(nsIProfileUnlocker**, nsIProfileLock**)&lt;br /&gt;
	0.0%	0.1%	XUL	   WriteVersion(nsIFile*, nsCString const&amp;amp;, nsCString const&amp;amp;, nsIFile*, nsIFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   nsINIParser_internal::Init(nsILocalFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   LaunchChildMac&lt;br /&gt;
	0.0%	0.4%	XUL	  XRE_GetBinaryPath&lt;br /&gt;
	0.3%	0.4%	XUL	  XRE_CreateAppData&lt;br /&gt;
	0.4%	0.4%	XUL	  NS_LogInit_P&lt;br /&gt;
	0.0%	6.2%	dyld	_dyld_start&lt;br /&gt;
	1.0%	1.0%	libSystem.B.dylib	_exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Breaking startup into smaller chunks ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: I really think that &amp;quot;Ts&amp;quot; is still much too large of a chunk to make meaningful improvements on&lt;br /&gt;
bsmedberg:joelr: in order to make meaninful discoveries, I think you have to break startup down into pieces and then maybe improve each piece&lt;br /&gt;
joelr:bsmedberg: i&#039;m listening&lt;br /&gt;
bsmedberg:well, you&#039;ve got various stuff that happens up until you start the event loop&lt;br /&gt;
bsmedberg:breaking XRE_main into phases up until nsAppStartup::Run would be interesting&lt;br /&gt;
bsmedberg:I still haven&#039;t seen a graph or anything of how we break down&lt;br /&gt;
bsmedberg:joelr: I think stepping through in a debugger might give you a better sense of what&#039;s going on (up until Run()) than profiles would&lt;br /&gt;
bsmedberg:even if you broke things up into &amp;quot;from main() to the beginning of event loop&amp;quot; and &amp;quot;after the event loop starts&amp;quot; that would be more interesting&lt;br /&gt;
bsmedberg:joelr: and then within the first chunk, timing NS_InitXPCOM, the extension manager bits, chromereg startup&lt;br /&gt;
bsmedberg:joelr: I think this intersects with some of the startup-timeline stuff taras was doing&lt;br /&gt;
joelr:bsmedberg: what are the functions for &amp;quot;extension manager bits&amp;quot; and &amp;quot;chromereg startup&amp;quot;?&lt;br /&gt;
bsmedberg:joelr: basically from http://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#2607 to #3453&lt;br /&gt;
joelr:bsmedberg: thanks for the suggestion, i&#039;ll do that&lt;br /&gt;
bsmedberg:joelr: #3382 to #3408 or so&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XUL reflow ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:joelr: so I&#039;m still wondering about some of the reflow stuff&lt;br /&gt;
bz:joelr: I know it&#039;s hard, but that&#039;s why no one&#039;s really dived into it yet&lt;br /&gt;
bz:joelr: and I&#039;d love to know whether we do in fact end up looping significantly in sprocket layout during startup, for example&lt;br /&gt;
joelr:bz: i&#039;m still wondering about reflow myself but i&#039;m not quite ready to tackle it yet&lt;br /&gt;
joelr:bz: don&#039;t know enough&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168762</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168762"/>
		<updated>2009-09-16T16:50:59Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* September 16, 2009 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 16, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== I&#039;m an idiot ====&lt;br /&gt;
&lt;br /&gt;
I spent a month becoming an expert on DTrace, only to realize that it&#039;s not very useful to get a global picture of the bottlenecks because the overhead of tracing everything is so high! &lt;br /&gt;
&lt;br /&gt;
Shark is a much better tool to get a global picture, specially using &amp;quot;Time profile all states&amp;quot; which allocates time spent blocking to the calling function. I overlooked this initially since I did not zero in on the right thread, the one that has &#039;&#039;start&#039;&#039; and &#039;&#039;XRE_main&#039;&#039; or &#039;&#039;exit&#039;&#039;. Without this it looks like Firefox is spending most of its time waiting on threads and Mach messages.&lt;br /&gt;
&lt;br /&gt;
==== Timing startup ====&lt;br /&gt;
&lt;br /&gt;
A clear picture courtesy of Shark&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	0.0%	92.8%	firefox-bin	start&lt;br /&gt;
	0.0%	92.8%	firefox-bin	 main&lt;br /&gt;
	0.0%	91.6%	XUL	  XRE_main&lt;br /&gt;
	0.0%	40.8%	XUL	   nsAppStartup::CreateHiddenWindow()&lt;br /&gt;
	0.0%	34.7%	XUL	   ScopedXPCOMStartup::Initialize()&lt;br /&gt;
	0.0%	6.4%	XUL	   ScopedXPCOMStartup::~ScopedXPCOMStartup()&lt;br /&gt;
	0.0%	3.4%	XUL	   ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport*)&lt;br /&gt;
	0.0%	2.4%	XUL	   nsXPTCStubBase::Stub3()&lt;br /&gt;
	0.0%	0.8%	XUL	   nsAppStartupNotifier::Observe(nsISupports*, char const*, unsigned short const*)&lt;br /&gt;
	0.0%	0.8%	HIToolbox	   GetCurrentEventKeyModifiers&lt;br /&gt;
	0.0%	0.6%	XUL	   nsXREDirProvider::DoStartup()&lt;br /&gt;
	0.0%	0.5%	XUL	   RemoveComponentRegistries(nsIFile*, nsIFile*, int)&lt;br /&gt;
	0.0%	0.4%	XUL	   NS_NewToolkitProfileService(nsIToolkitProfileService**)&lt;br /&gt;
	0.0%	0.3%	XUL	   nsToolkitProfile::Lock(nsIProfileUnlocker**, nsIProfileLock**)&lt;br /&gt;
	0.0%	0.1%	XUL	   WriteVersion(nsIFile*, nsCString const&amp;amp;, nsCString const&amp;amp;, nsIFile*, nsIFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   nsINIParser_internal::Init(nsILocalFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   LaunchChildMac&lt;br /&gt;
	0.0%	0.4%	XUL	  XRE_GetBinaryPath&lt;br /&gt;
	0.3%	0.4%	XUL	  XRE_CreateAppData&lt;br /&gt;
	0.4%	0.4%	XUL	  NS_LogInit_P&lt;br /&gt;
	0.0%	6.2%	dyld	_dyld_start&lt;br /&gt;
	1.0%	1.0%	libSystem.B.dylib	_exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Breaking startup into smaller chunks ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: I really think that &amp;quot;Ts&amp;quot; is still much too large of a chunk to make meaningful improvements on&lt;br /&gt;
bsmedberg:joelr: in order to make meaninful discoveries, I think you have to break startup down into pieces and then maybe improve each piece&lt;br /&gt;
joelr:bsmedberg: i&#039;m listening&lt;br /&gt;
bsmedberg:well, you&#039;ve got various stuff that happens up until you start the event loop&lt;br /&gt;
bsmedberg:breaking XRE_main into phases up until nsAppStartup::Run would be interesting&lt;br /&gt;
bsmedberg:I still haven&#039;t seen a graph or anything of how we break down&lt;br /&gt;
bsmedberg:joelr: I think stepping through in a debugger might give you a better sense of what&#039;s going on (up until Run()) than profiles would&lt;br /&gt;
bsmedberg:even if you broke things up into &amp;quot;from main() to the beginning of event loop&amp;quot; and &amp;quot;after the event loop starts&amp;quot; that would be more interesting&lt;br /&gt;
bsmedberg:joelr: and then within the first chunk, timing NS_InitXPCOM, the extension manager bits, chromereg startup&lt;br /&gt;
bsmedberg:joelr: I think this intersects with some of the startup-timeline stuff taras was doing&lt;br /&gt;
joelr:bsmedberg: what are the functions for &amp;quot;extension manager bits&amp;quot; and &amp;quot;chromereg startup&amp;quot;?&lt;br /&gt;
bsmedberg:joelr: basically from http://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#2607 to #3453&lt;br /&gt;
joelr:bsmedberg: thanks for the suggestion, i&#039;ll do that&lt;br /&gt;
bsmedberg:joelr: #3382 to #3408 or so&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XUL reflow ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:joelr: so I&#039;m still wondering about some of the reflow stuff&lt;br /&gt;
bz:joelr: I know it&#039;s hard, but that&#039;s why no one&#039;s really dived into it yet&lt;br /&gt;
bz:joelr: and I&#039;d love to know whether we do in fact end up looping significantly in sprocket layout during startup, for example&lt;br /&gt;
joelr:bz: i&#039;m still wondering about reflow myself but i&#039;m not quite ready to tackle it yet&lt;br /&gt;
joelr:bz: don&#039;t know enough&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168726</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168726"/>
		<updated>2009-09-16T12:20:48Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* Timing startup */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 16, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Timing startup ====&lt;br /&gt;
&lt;br /&gt;
A clear picture courtesy of Shark&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	0.0%	92.8%	firefox-bin	start&lt;br /&gt;
	0.0%	92.8%	firefox-bin	 main&lt;br /&gt;
	0.0%	91.6%	XUL	  XRE_main&lt;br /&gt;
	0.0%	40.8%	XUL	   nsAppStartup::CreateHiddenWindow()&lt;br /&gt;
	0.0%	34.7%	XUL	   ScopedXPCOMStartup::Initialize()&lt;br /&gt;
	0.0%	6.4%	XUL	   ScopedXPCOMStartup::~ScopedXPCOMStartup()&lt;br /&gt;
	0.0%	3.4%	XUL	   ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport*)&lt;br /&gt;
	0.0%	2.4%	XUL	   nsXPTCStubBase::Stub3()&lt;br /&gt;
	0.0%	0.8%	XUL	   nsAppStartupNotifier::Observe(nsISupports*, char const*, unsigned short const*)&lt;br /&gt;
	0.0%	0.8%	HIToolbox	   GetCurrentEventKeyModifiers&lt;br /&gt;
	0.0%	0.6%	XUL	   nsXREDirProvider::DoStartup()&lt;br /&gt;
	0.0%	0.5%	XUL	   RemoveComponentRegistries(nsIFile*, nsIFile*, int)&lt;br /&gt;
	0.0%	0.4%	XUL	   NS_NewToolkitProfileService(nsIToolkitProfileService**)&lt;br /&gt;
	0.0%	0.3%	XUL	   nsToolkitProfile::Lock(nsIProfileUnlocker**, nsIProfileLock**)&lt;br /&gt;
	0.0%	0.1%	XUL	   WriteVersion(nsIFile*, nsCString const&amp;amp;, nsCString const&amp;amp;, nsIFile*, nsIFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   nsINIParser_internal::Init(nsILocalFile*)&lt;br /&gt;
	0.0%	0.1%	XUL	   LaunchChildMac&lt;br /&gt;
	0.0%	0.4%	XUL	  XRE_GetBinaryPath&lt;br /&gt;
	0.3%	0.4%	XUL	  XRE_CreateAppData&lt;br /&gt;
	0.4%	0.4%	XUL	  NS_LogInit_P&lt;br /&gt;
	0.0%	6.2%	dyld	_dyld_start&lt;br /&gt;
	1.0%	1.0%	libSystem.B.dylib	_exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Breaking startup into smaller chunks ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: I really think that &amp;quot;Ts&amp;quot; is still much too large of a chunk to make meaningful improvements on&lt;br /&gt;
bsmedberg:joelr: in order to make meaninful discoveries, I think you have to break startup down into pieces and then maybe improve each piece&lt;br /&gt;
joelr:bsmedberg: i&#039;m listening&lt;br /&gt;
bsmedberg:well, you&#039;ve got various stuff that happens up until you start the event loop&lt;br /&gt;
bsmedberg:breaking XRE_main into phases up until nsAppStartup::Run would be interesting&lt;br /&gt;
bsmedberg:I still haven&#039;t seen a graph or anything of how we break down&lt;br /&gt;
bsmedberg:joelr: I think stepping through in a debugger might give you a better sense of what&#039;s going on (up until Run()) than profiles would&lt;br /&gt;
bsmedberg:even if you broke things up into &amp;quot;from main() to the beginning of event loop&amp;quot; and &amp;quot;after the event loop starts&amp;quot; that would be more interesting&lt;br /&gt;
bsmedberg:joelr: and then within the first chunk, timing NS_InitXPCOM, the extension manager bits, chromereg startup&lt;br /&gt;
bsmedberg:joelr: I think this intersects with some of the startup-timeline stuff taras was doing&lt;br /&gt;
joelr:bsmedberg: what are the functions for &amp;quot;extension manager bits&amp;quot; and &amp;quot;chromereg startup&amp;quot;?&lt;br /&gt;
bsmedberg:joelr: basically from http://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#2607 to #3453&lt;br /&gt;
joelr:bsmedberg: thanks for the suggestion, i&#039;ll do that&lt;br /&gt;
bsmedberg:joelr: #3382 to #3408 or so&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XUL reflow ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:joelr: so I&#039;m still wondering about some of the reflow stuff&lt;br /&gt;
bz:joelr: I know it&#039;s hard, but that&#039;s why no one&#039;s really dived into it yet&lt;br /&gt;
bz:joelr: and I&#039;d love to know whether we do in fact end up looping significantly in sprocket layout during startup, for example&lt;br /&gt;
joelr:bz: i&#039;m still wondering about reflow myself but i&#039;m not quite ready to tackle it yet&lt;br /&gt;
joelr:bz: don&#039;t know enough&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168724</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168724"/>
		<updated>2009-09-16T11:59:57Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* = Breaking startup into smaller chunks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 16, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Timing startup ====&lt;br /&gt;
&lt;br /&gt;
A clear picture courtesy of Shark&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	0.0%	87.7%	firefox-bin	start&lt;br /&gt;
	0.0%	87.7%	firefox-bin	 main&lt;br /&gt;
	0.0%	86.4%	XUL	  XRE_main&lt;br /&gt;
	0.0%	38.3%	XUL	   ScopedXPCOMStartup::Initialize()&lt;br /&gt;
	0.0%	30.9%	XUL	   nsAppStartup::CreateHiddenWindow()&lt;br /&gt;
	0.0%	11.1%	XUL	   ScopedXPCOMStartup::~ScopedXPCOMStartup()&lt;br /&gt;
	0.0%	2.5%	XUL	   nsXPTCStubBase::Stub3()&lt;br /&gt;
	0.0%	1.2%	XUL	   ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport*)&lt;br /&gt;
	0.0%	1.2%	XUL	   nsXREDirProvider::DoStartup()&lt;br /&gt;
	0.0%	1.2%	XUL	   nsAppStartupNotifier::Observe(nsISupports*, char const*, unsigned short const*)&lt;br /&gt;
	0.0%	1.2%	XUL	  XRE_GetBinaryPath&lt;br /&gt;
	0.0%	7.4%	dyld	_dyld_start&lt;br /&gt;
	4.9%	4.9%	libSystem.B.dylib	_exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Breaking startup into smaller chunks ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: I really think that &amp;quot;Ts&amp;quot; is still much too large of a chunk to make meaningful improvements on&lt;br /&gt;
bsmedberg:joelr: in order to make meaninful discoveries, I think you have to break startup down into pieces and then maybe improve each piece&lt;br /&gt;
joelr:bsmedberg: i&#039;m listening&lt;br /&gt;
bsmedberg:well, you&#039;ve got various stuff that happens up until you start the event loop&lt;br /&gt;
bsmedberg:breaking XRE_main into phases up until nsAppStartup::Run would be interesting&lt;br /&gt;
bsmedberg:I still haven&#039;t seen a graph or anything of how we break down&lt;br /&gt;
bsmedberg:joelr: I think stepping through in a debugger might give you a better sense of what&#039;s going on (up until Run()) than profiles would&lt;br /&gt;
bsmedberg:even if you broke things up into &amp;quot;from main() to the beginning of event loop&amp;quot; and &amp;quot;after the event loop starts&amp;quot; that would be more interesting&lt;br /&gt;
bsmedberg:joelr: and then within the first chunk, timing NS_InitXPCOM, the extension manager bits, chromereg startup&lt;br /&gt;
bsmedberg:joelr: I think this intersects with some of the startup-timeline stuff taras was doing&lt;br /&gt;
joelr:bsmedberg: what are the functions for &amp;quot;extension manager bits&amp;quot; and &amp;quot;chromereg startup&amp;quot;?&lt;br /&gt;
bsmedberg:joelr: basically from http://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#2607 to #3453&lt;br /&gt;
joelr:bsmedberg: thanks for the suggestion, i&#039;ll do that&lt;br /&gt;
bsmedberg:joelr: #3382 to #3408 or so&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XUL reflow ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:joelr: so I&#039;m still wondering about some of the reflow stuff&lt;br /&gt;
bz:joelr: I know it&#039;s hard, but that&#039;s why no one&#039;s really dived into it yet&lt;br /&gt;
bz:joelr: and I&#039;d love to know whether we do in fact end up looping significantly in sprocket layout during startup, for example&lt;br /&gt;
joelr:bz: i&#039;m still wondering about reflow myself but i&#039;m not quite ready to tackle it yet&lt;br /&gt;
joelr:bz: don&#039;t know enough&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168723</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168723"/>
		<updated>2009-09-16T11:58:49Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 16, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Timing startup ====&lt;br /&gt;
&lt;br /&gt;
A clear picture courtesy of Shark&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	0.0%	87.7%	firefox-bin	start&lt;br /&gt;
	0.0%	87.7%	firefox-bin	 main&lt;br /&gt;
	0.0%	86.4%	XUL	  XRE_main&lt;br /&gt;
	0.0%	38.3%	XUL	   ScopedXPCOMStartup::Initialize()&lt;br /&gt;
	0.0%	30.9%	XUL	   nsAppStartup::CreateHiddenWindow()&lt;br /&gt;
	0.0%	11.1%	XUL	   ScopedXPCOMStartup::~ScopedXPCOMStartup()&lt;br /&gt;
	0.0%	2.5%	XUL	   nsXPTCStubBase::Stub3()&lt;br /&gt;
	0.0%	1.2%	XUL	   ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport*)&lt;br /&gt;
	0.0%	1.2%	XUL	   nsXREDirProvider::DoStartup()&lt;br /&gt;
	0.0%	1.2%	XUL	   nsAppStartupNotifier::Observe(nsISupports*, char const*, unsigned short const*)&lt;br /&gt;
	0.0%	1.2%	XUL	  XRE_GetBinaryPath&lt;br /&gt;
	0.0%	7.4%	dyld	_dyld_start&lt;br /&gt;
	4.9%	4.9%	libSystem.B.dylib	_exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Breaking startup into smaller chunks ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: I really think that &amp;quot;Ts&amp;quot; is still much too large of a chunk to make meaningful improvements on&lt;br /&gt;
bsmedberg:joelr: in order to make meaninful discoveries, I think you have to break startup down into pieces and then maybe improve each piece&lt;br /&gt;
joelr:bsmedberg: i&#039;m listening&lt;br /&gt;
bsmedberg:well, you&#039;ve got various stuff that happens up until you start the event loop&lt;br /&gt;
bsmedberg:breaking XRE_main into phases up until nsAppStartup::Run would be interesting&lt;br /&gt;
bsmedberg:I still haven&#039;t seen a graph or anything of how we break down&lt;br /&gt;
bsmedberg:joelr: I think stepping through in a debugger might give you a better sense of what&#039;s going on (up until Run()) than profiles would&lt;br /&gt;
bsmedberg:even if you broke things up into &amp;quot;from main() to the beginning of event loop&amp;quot; and &amp;quot;after the event loop starts&amp;quot; that would be more interesting&lt;br /&gt;
bsmedberg:joelr: and then within the first chunk, timing NS_InitXPCOM, the extension manager bits, chromereg startup&lt;br /&gt;
bsmedberg:joelr: I think this intersects with some of the startup-timeline stuff taras was doing&lt;br /&gt;
joelr:bsmedberg: what are the functions for &amp;quot;extension manager bits&amp;quot; and &amp;quot;chromereg startup&amp;quot;?&lt;br /&gt;
bsmedberg:joelr: basically from http://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#2607 to #3453&lt;br /&gt;
joelr:bsmedberg: thanks for the suggestion, i&#039;ll do that&lt;br /&gt;
bsmedberg:joelr: #3382 to #3408 or so&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XUL reflow ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:joelr: so I&#039;m still wondering about some of the reflow stuff&lt;br /&gt;
bz:joelr: I know it&#039;s hard, but that&#039;s why no one&#039;s really dived into it yet&lt;br /&gt;
bz:joelr: and I&#039;d love to know whether we do in fact end up looping significantly in sprocket layout during startup, for example&lt;br /&gt;
joelr:bz: i&#039;m still wondering about reflow myself but i&#039;m not quite ready to tackle it yet&lt;br /&gt;
joelr:bz: don&#039;t know enough&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168189</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168189"/>
		<updated>2009-09-14T16:45:41Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* September 14, 2009 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== Breaking startup into smaller chunks ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: I really think that &amp;quot;Ts&amp;quot; is still much too large of a chunk to make meaningful improvements on&lt;br /&gt;
bsmedberg:joelr: in order to make meaninful discoveries, I think you have to break startup down into pieces and then maybe improve each piece&lt;br /&gt;
joelr:bsmedberg: i&#039;m listening&lt;br /&gt;
bsmedberg:well, you&#039;ve got various stuff that happens up until you start the event loop&lt;br /&gt;
bsmedberg:breaking XRE_main into phases up until nsAppStartup::Run would be interesting&lt;br /&gt;
bsmedberg:I still haven&#039;t seen a graph or anything of how we break down&lt;br /&gt;
bsmedberg:joelr: I think stepping through in a debugger might give you a better sense of what&#039;s going on (up until Run()) than profiles would&lt;br /&gt;
bsmedberg:even if you broke things up into &amp;quot;from main() to the beginning of event loop&amp;quot; and &amp;quot;after the event loop starts&amp;quot; that would be more interesting&lt;br /&gt;
bsmedberg:joelr: and then within the first chunk, timing NS_InitXPCOM, the extension manager bits, chromereg startup&lt;br /&gt;
bsmedberg:joelr: I think this intersects with some of the startup-timeline stuff taras was doing&lt;br /&gt;
joelr:bsmedberg: what are the functions for &amp;quot;extension manager bits&amp;quot; and &amp;quot;chromereg startup&amp;quot;?&lt;br /&gt;
bsmedberg:joelr: basically from http://mxr.mozilla.org/mozilla-central/source/toolkit/xre/nsAppRunner.cpp#2607 to #3453&lt;br /&gt;
joelr:bsmedberg: thanks for the suggestion, i&#039;ll do that&lt;br /&gt;
bsmedberg:joelr: #3382 to #3408 or so&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XUL reflow ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:joelr: so I&#039;m still wondering about some of the reflow stuff&lt;br /&gt;
bz:joelr: I know it&#039;s hard, but that&#039;s why no one&#039;s really dived into it yet&lt;br /&gt;
bz:joelr: and I&#039;d love to know whether we do in fact end up looping significantly in sprocket layout during startup, for example&lt;br /&gt;
joelr:bz: i&#039;m still wondering about reflow myself but i&#039;m not quite ready to tackle it yet&lt;br /&gt;
joelr:bz: don&#039;t know enough&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168181</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168181"/>
		<updated>2009-09-14T16:19:29Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: /* September 14, 2009 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
==== XPT_ArenaMalloc and zero-filling memory ====&lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bsmedberg:joelr: do you have evidence that the calloc is hurting? It really&lt;br /&gt;
doesn&#039;t sound like something that would take a lot of time&lt;br /&gt;
bsmedberg:there&#039;s no IO, and arena pages are roughly page-sized, right?&lt;br /&gt;
joelr:bsmedberg: i don&#039;t have evidence that it&#039;s hurting, not at all. i just&lt;br /&gt;
see it in the startup path a lot.&lt;br /&gt;
bsmedberg:&amp;quot;see it&amp;quot; in what way?&lt;br /&gt;
joelr:bsmedberg: there&#039;s no IO but arena pages are not page-sized. they are 1k&lt;br /&gt;
blocks whereas pages are 4k&lt;br /&gt;
joelr:bsmedberg: i&#039;m dtracing startup, all functions, that&#039;s how i see it&lt;br /&gt;
bsmedberg:it&#039;s less than a page, then... you really shouldn&#039;t be having&lt;br /&gt;
memory-thrashing issues with the calloc&lt;br /&gt;
bsmedberg:joelr: you mean it takes time, or its just a callcount?&lt;br /&gt;
bsmedberg:I&#039;m a little skeptical that the arena actually helps at all, but&lt;br /&gt;
that&#039;s a different matter.&lt;br /&gt;
joelr:bsmedberg: call count, i suppose. i&#039;m also skeptical that arena helps at&lt;br /&gt;
all since mac osx has it&#039;s own memory allocation optimizations&lt;br /&gt;
bsmedberg:And the xpt code has no tests, so unles you have a measured&lt;br /&gt;
performance problem I suggest not touching it.&lt;br /&gt;
joelr:bsmedberg: i see (tests)... well, i&#039;ll look into it a little bit more&lt;br /&gt;
since i want to measure a difference vs malloc (no zero-fill). it does crash&lt;br /&gt;
with malloc at the moment so i won&#039;t be looking into it too much.&lt;br /&gt;
bsmedberg:you&#039;d have to basically zero-fill when you allocate items from the&lt;br /&gt;
arena&lt;br /&gt;
joelr:bsmedberg: because those items expect to be zero-filled?&lt;br /&gt;
bsmedberg:seems so, if you&#039;re crashing with malloc...&lt;br /&gt;
bsmedberg:joelr: ok, well, I&#039;m saying &amp;quot;you have no evidence this bug is worth&lt;br /&gt;
fixing, please move on&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168179</id>
		<title>Firefox/Projects/Startup Time Improvements/joelr notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox/Projects/Startup_Time_Improvements/joelr_notes&amp;diff=168179"/>
		<updated>2009-09-14T16:16:31Z</updated>

		<summary type="html">&lt;p&gt;Joel Reymont: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Intro  =&lt;br /&gt;
&lt;br /&gt;
I&#039;m trying to figure out where Firefox startup time goes, up to the return from BrowserStartup (Javascript function). I&#039;m also manipulating DTrace into telling me where time is going, without making any assumptions.&lt;br /&gt;
&lt;br /&gt;
= Current status =&lt;br /&gt;
&lt;br /&gt;
=== September 14, 2009 === &lt;br /&gt;
&lt;br /&gt;
Closed [https://bugzilla.mozilla.org/show_bug.cgi?id=516241 Bug 516241]. There&#039;s no evidence that zero-filling memset is a bottleneck. DTrace cannot latch onto the return from memset on Snow Leopard, so I can&#039;t time it. All I know is that it&#039;s called 133,245 times during startup and zero-fills 14,851,995 bytes of memory.&lt;br /&gt;
&lt;br /&gt;
= Previous statuses = &lt;br /&gt;
&lt;br /&gt;
=== September 11, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflows ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
taras: joelr: btw, you gave up on reflows?&lt;br /&gt;
taras: that makes me sad&lt;br /&gt;
taras: i was hoping we&#039;d end up with some sort of tool to measure cost of laying out various xul components&lt;br /&gt;
joelr: taras: i did not give up, i just don&#039;t know how to go about it yet&lt;br /&gt;
taras: so people could profile their guis&lt;br /&gt;
taras: instead of going at it blindly&lt;br /&gt;
joelr: taras: i didn&#039;t hear your prayers, my apologies&lt;br /&gt;
joelr: i&#039;ll make a note on the idea of a tool that measures guis, though&lt;br /&gt;
joelr: taras: how do i measure? from where to where?&lt;br /&gt;
joelr: layout? reflow? something else?&lt;br /&gt;
taras: joelr: it&#039;s simple, time how long they take&lt;br /&gt;
taras: just see long functions take to run, ones that trigger all those fun reflow stacks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Restarting from the ground up ====&lt;br /&gt;
&lt;br /&gt;
I&#039;m very comfortable with DTrace but still not comfortable with the Firefox code base. It will take me a while to grok reflow, for example, much less optimize it. I feel that there are startup speedups that can be achieved quicker, with a better return on investment (aka low-hanging fruit).&lt;br /&gt;
&lt;br /&gt;
Yes, reflow is in the hot path during startup but it&#039;s not clear if it&#039;s a major source of slowness. I would like to know what happens during Firefox startup, in as much detail as possible and DTrace has granted me my wish in the form of a 400Mb+ log file. The file lists all the function calls up to the return from the JS function BrowserStartup, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    6200       .      .           -&amp;gt; ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)             &lt;br /&gt;
    6202       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
    6203      81      1             &amp;lt;- ImageLoaderMachOCompressed::segmentCommandOffsets() const = 10&lt;br /&gt;
    6205     270      4           &amp;lt;- ImageLoaderMachO::segIsReadOnlyImport(unsigned int) const = 116&lt;br /&gt;
    6206       .      .           -&amp;gt; ImageLoaderMachO::segFileOffset(unsigned int) const(0x8FE46820, 0x1, 0xBFFFC1C8)           &lt;br /&gt;
    6208       .      .             -&amp;gt; ImageLoaderMachOCompressed::segmentCommandOffsets() const(0x8FE46820, 0x0, 0x0)          &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are obviously interesting bits here. How can we piggyback on the &#039;&#039;ImageLoaderMachOCompressed&#039;&#039; for example?&lt;br /&gt;
&lt;br /&gt;
Minimizing file system access provides a good return on investment since it apparently takes a few milliseconds on mobile devices. I&#039;m focusing on this first and foremost since we do have file system access in the midst of dynamic linker static initialization, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
20974362 861470 708476        &amp;lt;- xptiSortFileList(void const*, void const*, void*) = 622&lt;br /&gt;
20974385 . .        -&amp;gt; xptiSortFileList(void const*, void const*, void*)(0x3050F9C, 0x3050F7C, 0xBFFFEBC0)		&lt;br /&gt;
20974394 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE978, 0xBFFFE98C, 0x0)		&lt;br /&gt;
20974397 113 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974400 . .        -&amp;gt; nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int)(0xBFFFE924, 0xBFFFE938, 0x0)		&lt;br /&gt;
20974402 112 2        &amp;lt;- nsACString_internal::nsACString_internal(char*, unsigned int, unsigned int) = 24&lt;br /&gt;
20974424 . .        -&amp;gt; nsLocalFile::GetNativeLeafName(nsACString_internal&amp;amp;)(0x3083600, 0xBFFFE978, 0x40)		&lt;br /&gt;
20974427 . .        -&amp;gt; objc_exception_try_enter(0xBFFFE868, 0xE000002, 0x181A4)		&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It may be interesting to study the startup path of Chromium and Safari.&lt;br /&gt;
&lt;br /&gt;
=== September 9, 2009 ===&lt;br /&gt;
&lt;br /&gt;
==== Reflow optimization ====&lt;br /&gt;
&lt;br /&gt;
I&#039;ve been thinking about speeding up reflows ([https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]) but did not make progress until I got Boris Zbarsky involved. There are tons and tons of classes that reflow and I&#039;m completely unfamiliar with that code. &lt;br /&gt;
&lt;br /&gt;
Boris suggested restricting invocations of PresShell::ProcessReflowCommands to those that actually do work&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0 != mDirtyRoots.Length()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
on XUL documents &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull) &amp;amp;&amp;amp;&lt;br /&gt;
FrameManager()-&amp;gt;GetRootFrame()-&amp;gt;GetFirstChild(nsnull)-&amp;gt;GetType() == nsGkAtoms::rootFrame&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399254 25 reflows and timings] for the &amp;quot;Getting involved with Mozilla...&amp;quot; page, it&#039;s clear that some reflows are more expensive than others. It&#039;s also interesting that there are [https://bug514275.bugzilla.mozilla.org/attachment.cgi?id=399445 just 11 reflows] for a blank page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz: 1) try to reduce number of reflows&lt;br /&gt;
bz: (e.g. make text controls not reflow sync in this setup if we can; reduce the number of text value sets if we can&#039;t)&lt;br /&gt;
bz: Or see whether the reflow events we get are really needed (e.g. if the load is not done yet, why are they happening?)&lt;br /&gt;
bz: But separately, it looks like reflows seem to be generally expensive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Performance measurement ====&lt;br /&gt;
&lt;br /&gt;
Using [http://blog.vlad1.com/2009/07/28/measuring-startup/ Vlad&#039;s benchmark], I have 5.3s cold start and 0.9s warm start. Timing using the return from [http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#903 BrowserStartup (JS)] gives me almost exactly the same results as Vlad&#039;s. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
javascript*:::function-return&lt;br /&gt;
/copyinstr(arg2) == &amp;quot;BrowserStartup&amp;quot;/&lt;br /&gt;
{&lt;br /&gt;
  exit(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The difference is about 50ms which copyinstr probably accounts for.&lt;br /&gt;
&lt;br /&gt;
=== September 3, 2009 ===&lt;br /&gt;
&lt;br /&gt;
On reflow...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bz:so there are a few things we could talk about:&lt;br /&gt;
bz:1) make any given reflow pass faster (this is hard)&lt;br /&gt;
bz:2) reduce number of reflow passes&lt;br /&gt;
bz:s/this is hard/this may be hard/&lt;br /&gt;
bz:So one place to start would be seeing why we&#039;re doing reflow at all&lt;br /&gt;
bz:that is, what things cause posting of reflow events and what things trigger reflow in their post-reflow callbacks&lt;br /&gt;
bz:and seeing whether we can reduce or eliminate them.&lt;br /&gt;
joelr:post-reflow callbacks?&lt;br /&gt;
bz:see comment 1 in the bug&lt;br /&gt;
bz:firefox has about 4000 elements in its ui&lt;br /&gt;
bz:which means about 4000 boxes to reflow&lt;br /&gt;
bz:modulo optimizations, etc&lt;br /&gt;
bz:BoxReflow is the reflow of a single box&lt;br /&gt;
bz:those are the two things to look into&lt;br /&gt;
bz:reducing number of reflow passes&lt;br /&gt;
bz:and speeding up individual passes&lt;br /&gt;
bz:if you have info on what parts actually take up time during reflow, we should look into that&lt;br /&gt;
bz:I would also be interested in the number of nsIFrame::Layout calls you see during startup&lt;br /&gt;
bz:that&#039;s a more interesting metric to me&lt;br /&gt;
bz:esp. if we can chunk it up per reflow pass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A reflow pass is &#039;&#039;PresShell::ProcessReflowCommands&#039;&#039; which can re-enter itself via post-reflow callbacks.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=514275 Bug 514275]&lt;br /&gt;
&lt;br /&gt;
=== September 2, 2009 ===&lt;br /&gt;
&lt;br /&gt;
My previous stack traces were all bogus since symbols are stripped during packaging. This is all sorted out now using this config (for Snow Leopard):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export CC=&amp;quot;gcc-4.2 -arch i386&amp;quot;&lt;br /&gt;
export CXX=&amp;quot;g++-4.2 -arch i386&amp;quot;&lt;br /&gt;
ac_add_options --target=i386-apple-darwin8.0.0&lt;br /&gt;
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk&lt;br /&gt;
ac_add_options --enable-macos-target=10.5&lt;br /&gt;
&lt;br /&gt;
export HOST_CC=&amp;quot;gcc-4.2&amp;quot;&lt;br /&gt;
export HOST_CXX=&amp;quot;g++-4.2&amp;quot;&lt;br /&gt;
export RANLIB=ranlib&lt;br /&gt;
export AR=ar&lt;br /&gt;
export AS=$CC&lt;br /&gt;
export LD=ld&lt;br /&gt;
export STRIP=&amp;quot;strip -x -S&amp;quot;&lt;br /&gt;
export CROSS_COMPILE=1&lt;br /&gt;
export MOZ_DEBUG_SYMBOLS=1&lt;br /&gt;
&lt;br /&gt;
. $topsrcdir/browser/config/mozconfig&lt;br /&gt;
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-release-profiling&lt;br /&gt;
mk_add_options MOZ_MAKE_FLAGS=-j2&lt;br /&gt;
ac_add_options --disable-tests&lt;br /&gt;
ac_add_options --disable-crashreporter&lt;br /&gt;
ac_add_options --enable-dtrace&lt;br /&gt;
ac_add_options --enable-libxul&lt;br /&gt;
ac_add_options --enable-optimize&lt;br /&gt;
ac_add_options --enable-debugger-info-modules&lt;br /&gt;
ac_add_options --disable-strip&lt;br /&gt;
ac_add_options --disable-install-strip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m getting 3-5s from cold start to return from &#039;&#039;BrowserStartup&#039;&#039; (JavaScript), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55752  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 5000.294085ms&lt;br /&gt;
&lt;br /&gt;
./d firefox-bin startup.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 55855  -s startup.d -s stop-js.d -s sigcont.d&lt;br /&gt;
&lt;br /&gt;
Total: 3387.623720ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hot path for those 5s looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-js.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 55765  -s hotpath.d -s stop-js.d -s sigcont.d&lt;br /&gt;
kill -CONT 55765&lt;br /&gt;
&lt;br /&gt;
  XUL`nsFrame::BoxReflow(nsBoxLayoutState&amp;amp;, nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsIRenderingContext*, int, int, int, int, int)             1382&lt;br /&gt;
  firefox-bin`0x0                                                 623&lt;br /&gt;
  XUL`nsHTMLInputElement::GetReadOnly(int*)                        53&lt;br /&gt;
  XUL`nsOverflowContinuationTracker::Insert(nsIFrame*, unsigned int&amp;amp;)               48&lt;br /&gt;
  XUL`MapAttributesIntoRule(nsMappedAttributes const*, nsRuleData*)               24&lt;br /&gt;
  XUL`nsBlockFrame::Reflow(nsPresContext*, nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;)               20&lt;br /&gt;
  XUL`nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&amp;amp;, nsHTMLReflowState const&amp;amp;, unsigned int&amp;amp;, nsColumnSetFrame::ReflowConfig const&amp;amp;, int, nsCollapsingMargin*, nsColumnSetFrame::ColumnBalanceData&amp;amp;)               18&lt;br /&gt;
  XUL`DocumentViewerImpl::PageHide(int)                            18&lt;br /&gt;
  XUL`nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&amp;amp;, nsLineLayout&amp;amp;, nsLineList_iterator, nsFlowAreaRect&amp;amp;, int&amp;amp;, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)               14&lt;br /&gt;
  XUL`non-virtual thunk to nsHTMLInputElement::Release()               11&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== August 30, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Using my &amp;quot;Lego blocks&amp;quot; [http://github.com/wagerlabs/firefox-startup/tree/master DTrace toolchain] I thought I would check the &amp;quot;hot paths&amp;quot; through Firefox code during the first 20 seconds of startup. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin hotpath.d stop-20s.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1478  -s hotpath.d -s stop-20s.d -s sigcont.d&lt;br /&gt;
kill -CONT 1478&lt;br /&gt;
&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)              2766&lt;br /&gt;
  firefox-bin`0x0                                                2234&lt;br /&gt;
  XUL`operator new(unsigned long, void*)                          348&lt;br /&gt;
  XUL`gfxImageSurface::Height() const                             335&lt;br /&gt;
  XUL`gfxPattern::Release()                                        60&lt;br /&gt;
  XUL`DumpJSValue                                                  44&lt;br /&gt;
  XUL`gfxContextAutoSaveRestore::gfxContextAutoSaveRestore(gfxContext*)               29&lt;br /&gt;
  XUL`gfxUserFontSet::Release()                                    17&lt;br /&gt;
  XUL`gfxImageSurface::Data() const                                16&lt;br /&gt;
  XUL`gfxContextPathAutoSaveRestore::~gfxContextPathAutoSaveRestore()                8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I&#039;m sampling at 997Hz so that&#039;s roughly 2.7s for the top result. A small script is all it took to see where &#039;&#039;gfxContextAutoSaveRestore::Reset&#039;&#039; is being called from.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
  i = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;lt; 10 /&lt;br /&gt;
{&lt;br /&gt;
  printf(&amp;quot;arg0: 0x%x, arg1: 0x%x\n&amp;quot;, arg0, arg1);&lt;br /&gt;
  ustack();&lt;br /&gt;
  i++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pid$target::gfxContextAutoSaveRestore??Reset(gfxContext*):return&lt;br /&gt;
/ i &amp;gt;= 10 / &lt;br /&gt;
{&lt;br /&gt;
  exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [http://gist.github.com/177980 stack traces] (first one of ten below) include &#039;&#039;gfxImageSurface::Height&#039;&#039; and &#039;&#039;DumpJSValue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin autosave.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1527  -s autosave.d -s sigcont.d&lt;br /&gt;
kill -CONT 1527&lt;br /&gt;
arg0: 0x90, arg1: 0x1a71da8&lt;br /&gt;
&lt;br /&gt;
              XUL`gfxContextAutoSaveRestore::Reset(gfxContext*)+0x90&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x2d976&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x135b6&lt;br /&gt;
              XUL`gfxImageSurface::Height() const+0x107b7&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53d16&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x53f1b&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x21cd&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x2324&lt;br /&gt;
              XUL`NS_GetComponentRegistrar_P+0x4964&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b3fd&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4b850&lt;br /&gt;
              XUL`non-virtual thunk to nsPrintSession::QueryInterface(nsID const&amp;amp;, void**)+0x4a9e1&lt;br /&gt;
              XUL`DumpJSValue+0x1dfbab&lt;br /&gt;
              XUL`DumpJSValue+0x1e0103&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xc9e8e&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xb64b4&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0xbb918&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x151bdf&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14e234&lt;br /&gt;
              XUL`gfxCornerSizes::gfxCornerSizes(gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;, gfxSize const&amp;amp;)+0x14ed99&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;gfxImageSurface::Height&#039;&#039; is low-hanging fruit, defined as &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRInt32 Height() const { return mSize.height; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I would suggest making it inline and checking startup time again. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;DumpJSValue&#039;&#039; is trickier because it appears to be a [http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/src/nsXPConnect.cpp#2714 JavaScript API function]. Still, it&#039;s called during the static initialization portion of dynamic linking and all that printing is not helping in a release version of Firefox.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin dump-js-value.d&lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=preinit -p 1579  -s dump-js-value.d -s sigcont.d&lt;br /&gt;
kill -CONT 1579&lt;br /&gt;
&lt;br /&gt;
              XUL`DumpJSValue+0x3917&lt;br /&gt;
              XUL`DumpJSValue+0x3b92&lt;br /&gt;
              XUL`0x111c146&lt;br /&gt;
              XUL`0x111c161&lt;br /&gt;
              dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&amp;amp;)+0xeb&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0xf6&lt;br /&gt;
              dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&amp;amp;, unsigned int)+0x9a&lt;br /&gt;
              dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&amp;amp;)+0x3d&lt;br /&gt;
              dyld`dyld::initializeMainExecutable()+0x86&lt;br /&gt;
              dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**)+0x105d&lt;br /&gt;
              dyld`dyldbootstrap::start(macho_header const*, int, char const**, long)+0x30b&lt;br /&gt;
              dyld`_dyld_start+0x27&lt;br /&gt;
              firefox-bin`0x1000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I suppose the invocation should only be compiled in in a debug version of Firefox but I&#039;m still searching for that invocation!&lt;br /&gt;
&lt;br /&gt;
=== August 28, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Eric Gouriou on my prior use of &#039;&#039;dtrace -c...&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
I am afraid that the data collected using this methodology is highly suspect.&lt;br /&gt;
&lt;br /&gt;
 - firefox-bin gets run as root&lt;br /&gt;
   This is not a normal environment for an application. There are plenty of high-level&lt;br /&gt;
   frameworks which are not quite happy running in that environment, in good part because&lt;br /&gt;
   the root user will not have a typical home directory setup and due to differences in environment&lt;br /&gt;
   variables.&lt;br /&gt;
&lt;br /&gt;
   This is a known limitation of dtrace -c . Feel free to add your voice via bugreporter.apple.com&lt;br /&gt;
&lt;br /&gt;
- A typical launch is not just fork/exec or posix_spawn&lt;br /&gt;
   Even if dtrace -c could magically launch using a regular user, it still isn&#039;t a typical launch.&lt;br /&gt;
   dtrace uses fork/exec or posix_spawn (I didn&#039;t check which one), while a typical launch&lt;br /&gt;
   (Dock, Finder, open) uses LaunchServices.  It isn&#039;t all that different but you might as well&lt;br /&gt;
   address both issues together.&lt;br /&gt;
&lt;br /&gt;
   I&#039;d recommend reworking your script to watch the exec-success of firefox-bin and use&lt;br /&gt;
   a static probe (no need for $target then) to mark the end time. Then you can use a more normal&lt;br /&gt;
   launch method, for example open .../Minefiled.app .&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I did [http://github.com/wagerlabs/firefox-startup/blob/75f719f3a3cdb380071ef8c354cf52564ac4754d/d rework my cold start script] which can be used like this now:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./d firefox-bin startup.d stop-main.d &lt;br /&gt;
dtrace -Zqw -x dynvarsize=64m -x evaltime=exec -p 35331 -s sigcont.d -s startup.d -s stop-main.d&lt;br /&gt;
kill -CONT 35331&lt;br /&gt;
Total: 2000.275985ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above assumes that I launch Minefield.app after &#039;&#039;d&#039;&#039;, from the dock, Finder, command line, etc.&lt;br /&gt;
&lt;br /&gt;
=== August 27, 2009 ===&lt;br /&gt;
&lt;br /&gt;
The dyld shared cache lives in &#039;&#039;/var/db/dyld/&#039;&#039;. The two files of interest are &#039;&#039;&#039;dyld_shared_cache_i386.map&#039;&#039;&#039; (for x86-32) and &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039;. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what &#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039; inspects.&lt;br /&gt;
&lt;br /&gt;
There&#039;s no prebinding on newer versions of Mac OSX and the dyld shared cache is&lt;br /&gt;
automatically updated as needed. Tracing Safari disk activity during startup&lt;br /&gt;
reveals that basically all its dynamic libraries are pulled from the dyld&lt;br /&gt;
shared cache. &lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add Firefox (&#039;&#039;.../Firefox.app/Contents/MacOS/firefox-bin&#039;&#039;) to&lt;br /&gt;
Applications.paths and the change will persist across reboots. Unfortunately,&lt;br /&gt;
only a handful of libraries that Firefox uses are pulled into the cache by&lt;br /&gt;
&#039;&#039;&#039;update_dyld_shared_cache&#039;&#039;&#039;. I&#039;m speculating that this may have something to do&lt;br /&gt;
with @executable_path/XUL and friends (otool -L .../firefox-bin). &lt;br /&gt;
&lt;br /&gt;
Safari uses absolute paths to frameworks in &#039;&#039;/System/Library/Frameworks&#039;&#039; so I&lt;br /&gt;
speculate that relative paths are what is preventing XUL and others from going&lt;br /&gt;
into the cache. We may want to investigate&lt;br /&gt;
&#039;&#039;/System/Library/Frameworks/Firefox.framework&#039;&#039; or similar.&lt;br /&gt;
&lt;br /&gt;
[https://bugzilla.mozilla.org/show_bug.cgi?id=513076 Bug 513076].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to fix relative library paths in a given library, e.g. &#039;&#039;fix.sh XUL&#039;&#039; where &#039;&#039;fix.sh&#039;&#039; looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
function dylibs () {&lt;br /&gt;
  otool -L $1 |grep executable_path|awk &#039;{print $1}&#039;|cut -d&amp;quot;/&amp;quot; -f2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for i in `dylibs $1`&lt;br /&gt;
do&lt;br /&gt;
        install_name_tool -change @executable_path/$i `pwd`/$i $1&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install_name_tool -id `pwd`/$1 $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firefox has to be recompiled with &#039;&#039;LDFLAGS=-header-pad_max_install_names&#039;&#039; in &#039;&#039;MOZCONFIG&#039;&#039; to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for &#039;&#039;&#039;install_name_tool&#039;&#039;&#039; for details.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to force dynamic libraries into the cache by putting dynamic library paths into &#039;&#039;&#039;shared_region_roots/Applications.paths&#039;&#039;&#039; instead of executables. I wasn&#039;t successful in caching XUL, though, regardless of what I did. &lt;br /&gt;
&lt;br /&gt;
In the end it doesn&#039;t seem to matter since there&#039;s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the cold startup stats for Safari&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; DYLD_PRINT_STATISTICS=1 /Applications/Safari.app/Contents/MacOS/Safari&lt;br /&gt;
total time: 696.9 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  116 (114 from dyld shared cache, 114 needed no fixups)&lt;br /&gt;
total segments mapped: 5, into 30 pages with 10 pages pre-fetched&lt;br /&gt;
total images loading time: 204.9 milliseconds (29.4%)&lt;br /&gt;
total rebase fixups:  1,298&lt;br /&gt;
total rebase fixups time: 0.1 milliseconds (0.0%)&lt;br /&gt;
total binding fixups: 2,476&lt;br /&gt;
total binding symbol lookups: 234, average images searched per symbol: 1.6&lt;br /&gt;
total binding fixups time: 80.5 milliseconds (11.5%)&lt;br /&gt;
total bindings lazily fixed up: 3 of 901&lt;br /&gt;
total init time time: 411.3 milliseconds (59.0%)&lt;br /&gt;
total images with weak exports:  1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and Firefox&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
total time: 731.2 milliseconds (100.0%)&lt;br /&gt;
total images loaded:  106 (93 from dyld shared cache, 56 needed no fixups)&lt;br /&gt;
total segments mapped: 49, into 5903 pages with 684 pages pre-fetched&lt;br /&gt;
total images loading time: 235.3 milliseconds (32.1%)&lt;br /&gt;
total rebase fixups:  149,011&lt;br /&gt;
total rebase fixups time: 3.7 milliseconds (0.5%)&lt;br /&gt;
total binding fixups: 24,932&lt;br /&gt;
total binding symbol lookups: 797, average images searched per symbol: 2.3&lt;br /&gt;
total binding fixups time: 149.9 milliseconds (20.5%)&lt;br /&gt;
total bindings lazily fixed up: 45 of 19,109&lt;br /&gt;
total init time time: 342.2 milliseconds (46.8%)&lt;br /&gt;
total images with weak exports:  3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice a large and significant difference? Me neither.&lt;br /&gt;
&lt;br /&gt;
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d&lt;br /&gt;
Total: 10001.723521ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?&lt;br /&gt;
&lt;br /&gt;
cold.sh is rather simple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZs $1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the startup.d script doesn&#039;t do much either&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#pragma D option quiet&lt;br /&gt;
&lt;br /&gt;
BEGIN&lt;br /&gt;
{&lt;br /&gt;
 start = timestamp;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* stop tracing here */&lt;br /&gt;
&lt;br /&gt;
mozilla$target:::main-entry&lt;br /&gt;
{&lt;br /&gt;
 exit(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
END&lt;br /&gt;
{&lt;br /&gt;
 this-&amp;gt;total = timestamp - start;&lt;br /&gt;
 printf(&amp;quot;Total: %u.%06ums\n&amp;quot;, this-&amp;gt;total / 1000000, this-&amp;gt;total % 1000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don&#039;t have an explanation yet but 9 seconds is a very large difference.&lt;br /&gt;
&lt;br /&gt;
=== August 26, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Suppose we sample at about 1Khz on a dual-core CPU and run an app for 10 seconds. An app that hogs the CPU should give us 20k samples, or 10k samples if it&#039;s pegged to a single core. &lt;br /&gt;
&lt;br /&gt;
I coded this up in a [http://github.com/wagerlabs/firefox-startup/blob/0daf8a950b91e8d9c24187d54b04fb51f2764490/cpu.d cpu.d] DTrace script and sampled Firefox. Apparently, Firefox only gets ~1700 samples on the CPU or 1.7s so its first 10 seconds of life are spent doing something else, e.g. disk IO.&lt;br /&gt;
&lt;br /&gt;
We already know that Firefox is slow to start up but this type of sampling neatly points the finger in the right direction. Props to Brendan Gregg for teaching me how to fish!&lt;br /&gt;
&lt;br /&gt;
What kind of IO does Firefox do upon startup, though? I find the output from &#039;&#039;iosnoop&#039;&#039; a bit confusing so I whipped up [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/io.d a version of my own] that prints just disk access times, disk operation deltas, block size and file name accessed. &lt;br /&gt;
&lt;br /&gt;
The script samples Firefox during the first 20 seconds of its life and the [http://pastie.org/595737 output from &#039;&#039;./cold.sh io.d&#039;&#039;] looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME      D    SIZE PATHNAME&lt;br /&gt;
1399       1407       R    4096 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1141       1145       R    8192 ??/dtrace/libdtrace_dyld.dylib&lt;br /&gt;
1301       1305       R    4096 ??/MacOS/XUL&lt;br /&gt;
1701       1705       R    4096 ??/MacOS/XUL&lt;br /&gt;
11081      685        R    4096 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1989       2253       R   36864 ??/MacOS/libmozjs.dylib&lt;br /&gt;
1768       1894       R   24576 ??/MacOS/libmozjs.dylib&lt;br /&gt;
27111      2135       R  200704 ??/MacOS/XUL&lt;br /&gt;
1411       1134       R    8192 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1784       1968       R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2383       464        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
2886       456        R    4096 ??/MacOS/libxpcom.dylib&lt;br /&gt;
1431       732        R    4096 ??/MacOS/libplds4.dylib&lt;br /&gt;
2640       706        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
3092       484        R    4096 ??/MacOS/libnspr4.dylib&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I also have [http://github.com/wagerlabs/firefox-startup/blob/7b78d70584bf9783d203e46786cbe800be4f5ba6/iosum.d a version that rolls disk operations by file name and read/write op]. It also samples during 20 seconds and [http://pastie.org/595727 outputs something like this]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DELTA      DTIME         SIZE D PATHNAME&lt;br /&gt;
307        311           4096 R ??/en_US.ISO8859-1/LC_TIME&lt;br /&gt;
437        441           4096 R ??/pref/firefox-branding.js&lt;br /&gt;
439        443           4096 R ??/su3x40q6.2/extensions.cache&lt;br /&gt;
441        445           4096 R ??/en_US.ISO8859-1/LC_NUMERIC&lt;br /&gt;
640        644           4096 R ??/en_US.ISO8859-1/LC_MONETARY&lt;br /&gt;
643        648           4096 R ??/chrome/browser.manifest&lt;br /&gt;
644        650           4096 R ??/la_LN.US-ASCII/LC_COLLATE&lt;br /&gt;
645        650           4096 R ??/Firefox/profiles.ini&lt;br /&gt;
646        650           4096 R ??/chrome/en-US.manifest&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All timings are in microseconds and specific to my Apple 256Gb SSD.&lt;br /&gt;
&lt;br /&gt;
There&#039;s something else that I discovered during my snooping around with io.d. Compare the first 20 seconds of [http://gist.github.com/175843 the life of Safari] and [http://gist.github.com/175842 the life of Firefox].&lt;br /&gt;
&lt;br /&gt;
Basically, all the shared libraries used by Safari are pulled in from the dynamic library shared cache. Safari uses mostly system frameworks, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGXCoreImage.A.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas Firefox uses a whole lot more custom shared libraries, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/HelpData&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
dyld: loaded: &lt;br /&gt;
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
dyld: loaded: /Library/Internet Plug-Ins/QuickTime Plugin.plugin/Contents/MacOS/QuickTime Plugin&lt;br /&gt;
dyld: loaded: /System/Library/QuickTime/QuickTimeComponents.component/Contents/MacOS/QuickTimeComponents&lt;br /&gt;
dyld: loaded: /System/Library/Frameworks/AGL.framework/Versions/A/AGL&lt;br /&gt;
dyld: loaded: /System/Library/PrivateFrameworks/CoreAUC.framework/Versions/A/CoreAUC&lt;br /&gt;
&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
dyld: loaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
dyld: unloaded: /Users/joelr/Work/mozilla/startup/Minefield.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I separated the list of libraries loaded by Firefox into three groups: same libraries as Safari, other system frameworks, custom libraries. &lt;br /&gt;
&lt;br /&gt;
What needs to be done to make Firefox use the dynamic library shared cache as aggressively as Safari?&lt;br /&gt;
&lt;br /&gt;
Another puzzling bit involves the difference between Safari libraries loaded by dyld (above) and the list of libraries that Safari is linked against, e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L  /Applications/Safari.app/Contents/MacOS/Safari &lt;br /&gt;
&lt;br /&gt;
	/System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/System/Library/Frameworks/Security.framework/Versions/A/Security&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation&lt;br /&gt;
	/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface&lt;br /&gt;
	/System/Library/PrivateFrameworks/SyndicationUI.framework/Versions/A/SyndicationUI&lt;br /&gt;
	/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz&lt;br /&gt;
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL&lt;br /&gt;
	/usr/lib/libicucore.A.dylib&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does Safari lazily loading some frameworks? Why do I see OpenGL initializers run when I set &#039;&#039;DYLD_PRINT_INITIALIZERS&#039;&#039; then? The OpenGL framework does not appear to be loaded when Safari starts (dyld output above).&lt;br /&gt;
&lt;br /&gt;
For the sake of comparing, here&#039;s the list of libraries that Firefox is linked against&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/firefox-bin./Minefield.app/Contents/MacOS/firefox-bin:&lt;br /&gt;
&lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/XUL&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libxpcom.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon&lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib &lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as well as the list of libraries for XUL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
otool -L ./Minefield.app/Contents/MacOS/XUL&lt;br /&gt;
&lt;br /&gt;
	@executable_path/XUL &lt;br /&gt;
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa&lt;br /&gt;
	@executable_path/libsqlite3.dylib&lt;br /&gt;
	@executable_path/libmozjs.dylib&lt;br /&gt;
	@executable_path/libsmime3.dylib&lt;br /&gt;
	@executable_path/libssl3.dylib&lt;br /&gt;
	@executable_path/libnss3.dylib&lt;br /&gt;
	@executable_path/libnssutil3.dylib&lt;br /&gt;
	@executable_path/libsoftokn3.dylib &lt;br /&gt;
	/usr/lib/libcups.2.dylib&lt;br /&gt;
	@executable_path/libplds4.dylib&lt;br /&gt;
	@executable_path/libplc4.dylib&lt;br /&gt;
	@executable_path/libnspr4.dylib&lt;br /&gt;
	/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration&lt;br /&gt;
	/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime&lt;br /&gt;
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit&lt;br /&gt;
	/usr/lib/libcrypto.0.9.7.dylib&lt;br /&gt;
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon &lt;br /&gt;
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio&lt;br /&gt;
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox&lt;br /&gt;
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit&lt;br /&gt;
	/System/Library/Frameworks/AddressBook.framework/Versions/A/AddressBook&lt;br /&gt;
	/usr/lib/libstdc++.6.dylib&lt;br /&gt;
	/usr/lib/libgcc_s.1.dylib&lt;br /&gt;
	/usr/lib/libSystem.B.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices&lt;br /&gt;
	/usr/lib/libobjc.A.dylib&lt;br /&gt;
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation&lt;br /&gt;
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit&lt;br /&gt;
	/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices&lt;br /&gt;
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It turns out that &#039;&#039;DYLD_PRINT_LIBRARIES=1&#039;&#039; is the way to show libraries loaded by dyld before a program&#039;s entry point (main) whereas &#039;&#039;DYLD_PRINT_LIBRARIES_POST_LAUNCH=1&#039;&#039; will show libraries loaded afterwards, e.g. using &#039;&#039;dlopen&#039;&#039; or &#039;&#039;NSBundle&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== August 25, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Created a [http://github.com/wagerlabs/firefox-startup/blob/c0b7691c60eb0455d7475aa17777edcf3ed3d605/main-entry-probe.patch static probe that fires first thing in XRE_main] and updated my [http://github.com/wagerlabs/firefox-startup/tree/master DTrace scripts] to use it. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pid$target::function:entry&#039;&#039; probes are very slow since DTrace may have to search thousands of functions. All that search time skews elapsed time reported by &#039;&#039;timestamp&#039;&#039;. USDT (static) probes are just a few NOP instructions in the code that get fixed up by DTrace as needed so they work much faster. &lt;br /&gt;
&lt;br /&gt;
=== August 24, 2009 ===&lt;br /&gt;
&lt;br /&gt;
Startup time is measured from the entry to XRE_main to the return of the BrowserStartup JS function. It takes a good bit of time but nothing compared to the time elapsed from the start of Firefox to the call to XRE_main. &lt;br /&gt;
&lt;br /&gt;
According to my [http://github.com/wagerlabs/firefox-startup/blob/8260ff9534f25eecf8e9e9feb590168815902a67/static-init.d static-init.d] script, the static initialization time can be ignored. I&#039;m recording the library name and then timing the following call to &#039;&#039;ImageLoader::runInitializers&#039;&#039; in dyld. The cumulative time is too small to be of essence, though.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.000053548s for /System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.000053732s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libsoftokn3.dylib&lt;br /&gt;
0.000069234s for /System/Library/PrivateFrameworks/Shortcut.framework/Versions/A/Shortcut&lt;br /&gt;
0.000070455s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/libnssckbi.dylib&lt;br /&gt;
0.000072754s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowsercomps.dylib&lt;br /&gt;
0.000073443s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/ATSHI.dylib&lt;br /&gt;
0.000074363s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCSync.A.dylib&lt;br /&gt;
0.000075845s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libCGATS.A.dylib&lt;br /&gt;
0.000076892s for /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Resources/libRIP.A.dylib&lt;br /&gt;
0.000089767s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libnssdbm3.dylib&lt;br /&gt;
0.000094390s for /Users/joelr/Work/mozilla/startup/./Minefield.app/Contents/MacOS/libfreebl3.dylib&lt;br /&gt;
0.000100462s for /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore&lt;br /&gt;
0.000115375s for /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox&lt;br /&gt;
0.001161267s for /Users/joelr/Work/mozilla/startup/MinefieldRelease.app/Contents/MacOS/components/libbrowserdirprovider.dylib&lt;br /&gt;
---------------&lt;br /&gt;
= 0.002181527s&lt;br /&gt;
&lt;br /&gt;
Initialization: 42.986413480s&lt;br /&gt;
Startup       : 7.015292701s&lt;br /&gt;
---------------&lt;br /&gt;
= 50.001706181s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Digging deeper...&lt;br /&gt;
&lt;br /&gt;
=== August 21, 2009 ===&lt;br /&gt;
&lt;br /&gt;
[http://wagerlabs.com/post/168237170/faster-mac-firefox Blogged].&lt;br /&gt;
&lt;br /&gt;
My DTrace scripts live [http://github.com/wagerlabs/firefox-startup/tree/master here]. Use like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./cold.sh static-init.d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= DTrace tips and tricks =&lt;br /&gt;
&lt;br /&gt;
=== DTrace overhead and proper measuring technique ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mail-archive.com/dtrace-discuss@opensolaris.org/msg03639.html I&#039;m still not done!]&lt;br /&gt;
&lt;br /&gt;
=== Function entry/return vs static probes ===&lt;br /&gt;
&lt;br /&gt;
Q: I added a couple of static probes to Firefox to measure actual work done. I could have used a pid$target probe with a function name but work is done within an if statement, which is where I placed the static probes. I&#039;m wondering about my use, though. Is the following significantly more&lt;br /&gt;
efficient than pid$target::FunName:entry and return?&lt;br /&gt;
&lt;br /&gt;
A: No, it&#039;s not significantly more efficient.  Both function entry/return probes and USDT probes involve replacing an instruction in the stream with a trap instruction.  The expense of the trap into the kernel is going to overwhelm any subtleties in handling between the two different types of probes. --Chad Mynhier&lt;br /&gt;
&lt;br /&gt;
=== Combining scripts ===&lt;br /&gt;
&lt;br /&gt;
I find it convenient to have separate DTrace scripts for various exit probes. This way I can avoid editing the main script whenever I want to stop sampling once 10 seconds go by or &#039;&#039;XRE_main&#039;&#039; is entered or the &#039;&#039;BrowserReturn&#039;&#039; JavaScript function returns.&lt;br /&gt;
&lt;br /&gt;
It can be done like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash &lt;br /&gt;
&lt;br /&gt;
cmd=&amp;quot;./Minefield.app/Contents/MacOS/firefox-bin -no-remote -foreground -P 2&amp;quot;&lt;br /&gt;
scripts=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for i in $*; do scripts=&amp;quot;$scripts -s $i&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
sync &amp;amp;&amp;amp; purge &amp;amp;&amp;amp; dtrace -x dynvarsize=64m -x evaltime=exec -c &amp;quot;$cmd&amp;quot; -wZ $scripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and then &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-main.d &lt;br /&gt;
Total: 11001.481323ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
./cold.sh startup.d stop-js.d &lt;br /&gt;
Total: 7004.799264ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My scripts can be [http://github.com/wagerlabs/firefox-startup/tree/master found on GitHub].&lt;br /&gt;
&lt;br /&gt;
=== No sudo ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo chmod u+s `which dtrace`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now run dtrace as yourself. Enjoy!&lt;br /&gt;
&lt;br /&gt;
=== timestamp vs vtimestamp ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;vtimestamp&#039;&#039; measures CPU time of the current thread, excluding IO and DTrace overhead. &#039;&#039;timestamp&#039;&#039; can still be used for deltas but the goal is to use as few pid$target probes as possible as they affect &#039;&#039;timestamp&#039;&#039; when dtrace has to switch between kernel and userland. io and syscall providers are fast and run in the kernel.&lt;br /&gt;
&lt;br /&gt;
=== Invalid address ===&lt;br /&gt;
&lt;br /&gt;
Have you seen this kind of error before?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dtrace: error on enabled probe ID 27 (ID 22130: pid34547:libSystem.B.dylib:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
dtrace: error on enabled probe ID 2 (ID 22782: pid34547:dyld:dlopen:entry): invalid address (0x2ac204) in action #1 at DIF offset 28&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More likely than not, you are using copyinstr on memory that hasn&#039;t been paged in yet. Try saving the pointer on entry and doing the copying on return or later.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Joel Reymont</name></author>
	</entry>
</feed>