{"id":444,"date":"2011-01-07T13:04:14","date_gmt":"2011-01-07T02:04:14","guid":{"rendered":"http:\/\/blog.mozilla.org\/nnethercote\/?p=444"},"modified":"2011-01-07T13:04:14","modified_gmt":"2011-01-07T02:04:14","slug":"memory-profiling-firefox-with-massif-part-2","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/nnethercote\/2011\/01\/07\/memory-profiling-firefox-with-massif-part-2\/","title":{"rendered":"Memory profiling Firefox with Massif, part 2"},"content":{"rendered":"<p>To follow up from <a href=\"http:\/\/blog.mozilla.org\/nnethercote\/2010\/12\/09\/memory-profiling-firefox-with-massif\/\">this post<\/a>: we&#8217;ve made some good progress on reducing JaegerMonkey&#8217;s memory consumption in Firefox 4, though there&#8217;s still a way to go.\u00a0 Julian Seward will <a href=\"http:\/\/blog.mozilla.org\/jseward\/\">blog<\/a> about this shortly.\u00a0 In the meantime, I thought I&#8217;d share a particularly useful Massif invocation that Rob Sayre inspired me to concoct:<\/p>\n<pre>  valgrind \\\r\n  --smc-check=all --trace-children=yes \\\r\n  --tool=massif \\\r\n  --pages-as-heap=yes --detailed-freq=1000000 \\\r\n  --threshold=0.5 \\\r\n  --alloc-fn=mmap \\\r\n  --alloc-fn=syscall \\\r\n  --alloc-fn=pages_map \\\r\n  --alloc-fn=chunk_alloc \\\r\n  --alloc-fn=arena_run_alloc \\\r\n  --alloc-fn=arena_bin_malloc_hard \\\r\n  --alloc-fn=malloc \\\r\n  --alloc-fn=realloc \\\r\n  --alloc-fn='operator new(unsigned long)' \\\r\n  --alloc-fn=huge_malloc \\\r\n  --alloc-fn=posix_memalign \\\r\n  --alloc-fn=moz_xmalloc \\\r\n  --alloc-fn=JS_ArenaAllocate \\\r\n  --alloc-fn=PL_ArenaAllocate \\\r\n  --alloc-fn=NS_Alloc_P \\\r\n  --alloc-fn=NS_Realloc_P \\\r\n  --alloc-fn='XPConnectGCChunkAllocator::doAlloc()' \\\r\n  --alloc-fn='PickChunk(JSRuntime*)' \\\r\n  --alloc-fn='RefillFinalizableFreeList(JSContext*, unsigned int)' \\\r\n  --alloc-fn=sqlite3MemMalloc \\\r\n  --alloc-fn=mallocWithAlarm \\\r\n  --alloc-fn=sqlite3Malloc \\\r\n  &lt;insert-firefox-command-here&gt;\r\n<\/pre>\n<p>Good grief!\u00a0 What a mess.\u00a0 Don&#8217;t blame Massif for this, though;\u00a0 it&#8217;s because Firefox has so many custom memory allocators.<\/p>\n<p>With that invocation, the output of ms_print becomes something that is comprehensible to people other than Massif&#8217;s author \ud83d\ude42\u00a0 Here&#8217;s an extraction of the output which gives a high-level view of Firefox&#8217;s memory consumption on 64-bit Linux after loading 20 tabs, each with a random comic from <a href=\"http:\/\/www.cad-comic.com\/cad\/\">http:\/\/www.cad-comic.com\/cad\/<\/a>, which is a JavaScript-heavy site:<\/p>\n<pre>31.04% (366,878,720B) _dl_map_object_from_fd (dl-load.c:1195)\r\n15.73% (185,998,724B) in 3693 places, all below massif's threshold (00.00%)\r\n15.62% (184,639,488B) pthread_create@@GLIBC_2.2.5 (allocatestack.c:483)\r\n05.68% (67,112,960B) pa_shm_create_rw (in \/usr\/lib\/libpulsecommon-0.9.21.so)\r\n04.35% (51,372,032B) JSC::ExecutablePool::systemAlloc(unsigned long) (ExecutableAllocatorPosix.cpp:43)\r\n03.30% (38,993,920B) js::InitJIT(js::TraceMonitor*) (jstracer.cpp:7644)\r\n03.11% (36,741,120B) js::InitJIT(js::TraceMonitor*) (jstracer.cpp:7643)\r\n02.87% (33,935,360B) js::PropertyTree::newShape(JSContext*, bool) (jspropertytree.cpp:97)\r\n02.84% (33,554,432B) js_NewFunction(JSContext*, JSObject*, int (*)(JSContext*, unsigned int, js::Value*), unsigned int, unsigned int, JSObject*, JSAtom*) (jsgcinlines.h:127)\r\n02.79% (32,923,648B) js::InitJIT(js::TraceMonitor*) (jstracer.cpp:7642)\r\n01.99% (23,555,684B) js::mjit::Compiler::finishThisUp(js::mjit::JITScript**) (jsutil.h:213)\r\n01.69% (19,934,784B) JSScript::NewScript(JSContext*, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned short, unsigned short) (jsutil.h:209)\r\n01.53% (18,067,456B) pcache1Alloc (sqlite3.c:33368)\r\n01.48% (17,457,388B) nsStringBuffer::Alloc(unsigned long) (nsSubstring.cpp:206)\r\n01.31% (15,478,784B) g_mapped_file_new (in \/lib\/libglib-2.0.so.0.2400.1)\r\n00.89% (10,486,784B) JS_NewObject (jsgcinlines.h:127)\r\n00.71% (8,388,608B) js::StackSpace::init() (jscntxt.cpp:164)\r\n00.68% (8,093,696B) GCGraphBuilder::NoteScriptChild(unsigned int, void*) (mozalloc.h:229)\r\n00.68% (8,024,064B) NewOrRecycledNode(JSTreeContext*) (jsparse.cpp:495)\r\n00.67% (7,974,936B) js::Vector&lt;unsigned short, 32ul, js::ContextAllocPolicy&gt;::growStorageBy(unsigned long) (jsutil.h:217)\r\n00.53% (6,291,456B) js_CloneRegExpObject(JSContext*, JSObject*, JSObject*) (jsgcinlines.h:127)\r\n00.52% (6,190,836B) nsTArray_base&lt;nsTArrayDefaultAllocator&gt;::EnsureCapacity(unsigned int, unsigned int) (nsTArray.h:68)\r\n<\/pre>\n<p>The total is 1,182,094,880 bytes.<\/p>\n<ul>\n<li>31.04% is from <code>_dl_map_object_from_fd<\/code>.\u00a0 This corresponds to code and data segments, mostly from libraries.<\/li>\n<li>15.73% is from allocation points small enough that they fell below the threshold (0.5%) that I used for this run.<\/li>\n<li>15.62% is from <code>pthread_create<\/code>, i.e. thread stacks.\u00a0 Hopefully most of this space also won&#8217;t be mapped in.<\/li>\n<li>5.68% is from <code>pa_shm_create_rw<\/code>.\u00a0 <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=617852\">Bug 617852<\/a> is open about this.\u00a0 It won&#8217;t be fixed until after Firefox 4.0, but that&#8217;s not so bad because \/proc\/pid\/smaps tells me that hardly any of it is mapped into physical memory.<\/li>\n<li>That leaves 31.93% of big, heap-ish allocations.\u00a0 It&#8217;s pretty obvious that for this workload, the JS engine is being greedy, accounting for 26.42% of that 31.83%.\u00a0 One piece of good news is that the three <code>js::InitJIT()<\/code> entries, which together account for 9.2%, will be greatly improved by <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=623428\">bug 623428<\/a>;\u00a0 I&#8217;m hoping to reduce them by a factor of 10 or more.<\/li>\n<\/ul>\n<p>If anyone wants Massif&#8217;s full output, I&#8217;ll be happy to give it to them.\u00a0 The full output contains full stack traces, which can be useful.<\/p>\n<p>Some conclusions.<\/p>\n<ul>\n<li>I&#8217;m still worred about our memory consumption, and I intend to keep pushing on it, both before Firefox 4.0 is released and afterwards.<\/li>\n<li>Massif takes a bit of getting used to, particularly when you are profiling a huge, messy program like Firefox.\u00a0 But it&#8217;s the only space profiler I know of that gives information that is detailed enough to be really useful in reducing memory consumption.\u00a0 Without it, we wouldn&#8217;t have made much progress on reducing Firefox 4.0&#8217;s space consumption.\u00a0 I&#8217;d love for other people to run it, it works on Linux and Mac (not Windows, unfortunately).\u00a0 I&#8217;m happy to help anyone who wants to try it via IRC or email.\u00a0 For all the improvements done lately, I&#8217;ve only looked at a single workload on a single machine!\u00a0 There&#8217;s much more analysis to be done.<\/li>\n<li>If anyone knows of other decent memory profilers that can handle programs as complex as Firefox, I&#8217;d love to hear about it.\u00a0 In particular, note that if you only measure the heap (malloc et al) you&#8217;re only getting part of the story;\u00a0 this is again because we have multiple allocators which bypass malloc and use <code>mmap<\/code>\/<code>VirtualAlloc<\/code> directly.<\/li>\n<li>I wonder if we need better memory benchmarks.\u00a0 I&#8217;d like to have some that are as easy to run as, say, SunSpider. \u00a0<a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=585196\">Better telemetry<\/a> would also be great.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>To follow up from this post: we&#8217;ve made some good progress on reducing JaegerMonkey&#8217;s memory consumption in Firefox 4, though there&#8217;s still a way to go.\u00a0 Julian Seward will blog about this shortly.\u00a0 In the meantime, I thought I&#8217;d share a particularly useful Massif invocation that Rob Sayre inspired me to concoct: valgrind \\ &#8211;smc-check=all [&hellip;]<\/p>\n","protected":false},"author":139,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[30,4543,4545,4544,484],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/posts\/444"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/users\/139"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/comments?post=444"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/posts\/444\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/media?parent=444"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/categories?post=444"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/tags?post=444"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}