Analyzing the Performance of Mobile Web: Challenges and Techniques ARIYA HIDAYAT ENGINEERING DIRECTOR
Going Under the Hood
whoami
Overview
Performance Areas Network Graphics JavaScript
Desktop Tools WebMetrics Web Inspector Page Speed Firebug Speed Tracer YSlow Blaze.io dynaTrace WebPageTest pcapperf
Mobile Situation Continous Integration Metrics • framerate • bytes transferred • caching • cookies • cache manifest • code size • execution speed Network Variances 2G, EDGE, 3G, 4G, LTE, ...
“Too Many Phones Will Kill You...”
Stake Holders Web Site Developers Service Provider Application Developers Browser vendors
Approaches High-speed Camera Benchmark RF Monitor Inject instrumentation Proxy Remote Read the inspection source code Observation Emulation Intrusive
Strategies Reducing complexity Replicate and/or analyze on desktop 1 2 Tweak and insert instrumentation System level
Caveats Concept Focus
Tools of Trade Gingerbread Nexus One http://source.android.com/source/building-devices.html
Headless WebKit “Full web stack. No browser required” http://www.phantomjs.org https://github.com/ariya/phantomjs
Source Code WebKit http://www.webkit.org/ http://android.git.kernel.org/?p=platform/external/webkit.git http://opensource.apple.com/ V8 http://code.google.com/p/v8/
WebCore Different WebKit “Ports” graphics Mac Chromium iOS Android Qt Gtk GraphicsContext Skia Cairo CoreGraphics QPainter graphics stack
Network
“Understanding Mobile Web Browser Performance” Rajiv Vijayakumar (Qualcomm) Wed 2:40 pm, Ballroom ABCD
Web Inspector Network
http://www.softwareishard.com/blog/har-12-spec/ HTTP Archive (HAR)
Automating Network Sniffing (Desktop) phantomjs netsniff.js http://m.bing.com Visualize using online HAR viewer
Android WebKit + Network Stack Java Browser Java Network Stack WebView Java JNI libwebcore C++
Real-time Sniffing + Postprocessing WebFrame::startLoadingResource WebCoreResourceLoader::AddData(...) waiting data transfer WebCoreResourceLoader::Finished()
Example: Orchid adb logcat -v time | grep NETWORK 06-12 22:57:48.430 D/webcoreglue( 1357): startLoadingResource NETWORK 0x66d368 http://en.m.wikipedia.org/wiki/ Orchid 06-12 22:57:48.710 D/webcoreglue( 1357): ReceivedResponse NETWORK handle=0x66d368 mimeType=text/html url=http:// en.m.wikipedia.org/wiki/Orchid 06-12 22:57:48.780 D/webcoreglue( 1357): startLoadingResource NETWORK 0x6a8678 http://en.m.wikipedia.org/ stylesheets/android.css 06-12 22:57:48.780 D/webcoreglue( 1357): startLoadingResource NETWORK 0x6ab388 http://en.m.wikipedia.org/ javascripts/jquery.js 06-12 22:57:48.790 D/webcoreglue( 1357): startLoadingResource NETWORK 0x6ab7e8 http://en.m.wikipedia.org/ javascripts/application.js 06-12 22:57:48.790 D/webcoreglue( 1357): AddData NETWORK 0x66d368 4162 http://en.m.wikipedia.org/wiki/Orchid 06-12 22:57:48.790 D/webcoreglue( 1357): AddData NETWORK 0x66d368 8192 http://en.m.wikipedia.org/wiki/Orchid 06-12 22:57:48.790 D/webcoreglue( 1357): AddData NETWORK 0x66d368 1361 http://en.m.wikipedia.org/wiki/Orchid 06-12 22:57:48.980 D/webcoreglue( 1357): AddData NETWORK 0x66d368 8192 http://en.m.wikipedia.org/wiki/Orchid 06-12 22:57:48.980 D/webcoreglue( 1357): AddData NETWORK 0x66d368 803 http://en.m.wikipedia.org/wiki/Orchid 06-12 22:57:49.000 D/webcoreglue( 1357): AddData NETWORK 0x66d368 4702 http://en.m.wikipedia.org/wiki/Orchid 06-12 22:57:49.000 D/webcoreglue( 1357): AddData NETWORK 0x66d368 4507 http://en.m.wikipedia.org/wiki/Orchid 06-12 22:57:49.020 D/webcoreglue( 1357): AddData NETWORK 0x66d368 8192 http://en.m.wikipedia.org/wiki/Orchid 06-12 22:57:49.050 D/webcoreglue( 1357): AddData NETWORK 0x66d368 6750 http://en.m.wikipedia.org/wiki/Orchid
Example: Orchid
Going Offline: Cache Manifest Automatic local storage optimization phantomjs confess.js http://functionsource.com https://github.com/jamesgpearce/confess
Graphics
Drawing Command Analysis Log file WebCore graphics GraphicsContext Skia
Example: Bing platformInit savePlatformState translate 0,0 translate 0,0 clip 1,0 0x6.95322e-310 fillRect 0,0 800x556 color ff ff ff ff restorePlatformState platformDestroy platformInit savePlatformState translate 0,0 translate 0,0 clip 1,0 0x6.95322e-310 fillRect 0,0 800x556 color ff ff ff ff restorePlatformState platformDestroy platformInit savePlatformState translate 0,0 translate 0,0 clip 1,0 0x6.95322e-310 fillRect 0,0 800x556 color ff ff ff ff fillRect 0,0 800x556 color ff ff ff ff
Painting Traces
Display List Aproach no overhead anmore WebKit GraphicsContext “SkPicture” Skia
How Fast is the “Playback”? #include "TimeCounter.h" bool WebViewCore::drawContent(SkCanvas* canvas, SkColor) { uint32_t timestamp = getThreadMsec(); .... painting code .... DBG_SET_LOGD("% ms", getThreadMsec() - timestamp); } external/webkit/WebKit/android/jni/WebViewCore.cpp
Example: Google News adb logcat -v time | grep drawContent 16:24:04.070 D/webcoreglue( 273): drawContent 11 ms 16:24:04.110 D/webcoreglue( 273): drawContent 13 ms 16:24:04.150 D/webcoreglue( 273): drawContent 13 ms 16:24:04.190 D/webcoreglue( 273): drawContent 10 ms 16:24:04.240 D/webcoreglue( 273): drawContent 10 ms 16:24:04.280 D/webcoreglue( 273): drawContent 13 ms 16:24:04.320 D/webcoreglue( 273): drawContent 13 ms 16:24:04.360 D/webcoreglue( 273): drawContent 13 ms 16:24:06.080 D/webcoreglue( 273): drawContent 12 ms 16:24:06.140 D/webcoreglue( 273): drawContent 10 ms 16:24:06.180 D/webcoreglue( 273): drawContent 13 ms 16:24:06.230 D/webcoreglue( 273): drawContent 14 ms 16:24:06.600 D/webcoreglue( 273): drawContent 26 ms 16:24:06.640 D/webcoreglue( 273): drawContent 13 ms 16:24:06.860 D/webcoreglue( 273): drawContent 33 ms 16:24:06.890 D/webcoreglue( 273): drawContent 12 ms 16:24:06.930 D/webcoreglue( 273): drawContent 13 ms 16:24:06.960 D/webcoreglue( 273): drawContent 13 ms 16:24:07.000 D/webcoreglue( 273): drawContent 13 ms
How Much is the Frame Rate? bool WebViewCore::drawContent(SkCanvas* canvas, SkColor color) { static uint32_t frame_ref = 0; static int frame_tick = 0; ... painting code ... frame_tick++; if (frame_tick >= 10) { DBG_SET_LOGD("framerate %d fps", (int)(frame_tick * 1000 / (1 + getThreadMsec() - frame_ref))); frame_tick = 0; frame_ref = getThreadMsec(); } }
Site Mirroring Intertubes port 8080 SQLite DB Proxy Mirror port 8081 network/netspiegel https://github.com/ariya/X2
JavaScript
http://www.sencha.com/blog/remote-javascript-debugging-on-android/ Remote Console http://github.com/senchalabs/android-tools
Garbage Collector bool Heap::CollectGarbage(int requested_size, AllocationSpace space) { .. some code ... PerformGarbageCollection(space, collector, &tracer); LOGD("PerformGarbageCollection %d", requested_size); .. some code ... } external/v8/src/heap.cc
Example: Travelmate adb logcat -v time | grep GarbageCollection 06-13 13:24:36.470 D/v8 ( 532): PerformGarbageCollection 20 06-13 13:24:36.630 D/v8 ( 532): PerformGarbageCollection 32788 06-13 13:24:36.740 D/v8 ( 532): PerformGarbageCollection 116 06-13 13:24:36.810 D/v8 ( 532): PerformGarbageCollection 88 06-13 13:24:36.870 D/v8 ( 532): PerformGarbageCollection 52 06-13 13:24:37.000 D/v8 ( 532): PerformGarbageCollection 20 06-13 13:24:37.090 D/v8 ( 532): PerformGarbageCollection 24 06-13 13:24:37.450 D/v8 ( 532): PerformGarbageCollection 35884 06-13 13:24:39.400 D/v8 ( 532): PerformGarbageCollection 20 06-13 13:24:39.730 D/v8 ( 532): PerformGarbageCollection 3392
Keyword vs Identifier instanceof instanceComponent requires checking 9 chars a g h j k l m o p q x y z
Function Parsing Analyze the syntax foobar = function(x, y, z) Mark the position of { function ‘foobar’ .... } foobar(x, y, z); Compile and run the function ‘foobar’
Static Code Analysis hammerjs --syntax source-file.js JSON syntax tree Reflect.parse(code) https://github.com/senchalabs/hammerjs
Syntax Tree Variable Declaration number identifier var answer = 42; keyword equal sign Identifier Literal Constant answer 42
"type": "IfStatement", "test": { "type": "BinaryExpression", "operator": "==", "left": { "type": "Identifier", "name": "x" }, "right": { "type": "Identifier", "name": "y" } if (x == y) foo(); }, "consequent": { "type": "ExpressionStatement", "expression": { "type": "CallExpression", Danger! "callee": { "type": "Identifier", "name": "foo" }, "arguments": [] } }, "alternate": null
Deploy-time Pruning Never used function createList(position, options) { ... some code ... } createList({ x: 0, y: 0}); createList({ x: 0, y: 100});
Avoid Object Construction Create + Destroy startTime = new Date(); startTime = Date.now(); // heavy processing // heavy processing elapsed = (new Date()) - startTime; elapsed = Date.now() - startTime;
Recommend
More recommend