Analyzing the Performance of Mobile Web: Challenges and Techniques ARIYA HIDAYAT ENGINEERING DIRECTOR
Apr 24, 2015
Analyzing the Performance of Mobile Web:
Challenges and Techniques
ARIYA HIDAYATENGINEERING DIRECTOR
whoami
Going Under the Hood
MyOwnSlow
Overview
Performance Areas
Network
Graphics
JavaScript
Desktop Tools
Firebug
Web Inspector
dynaTrace
Speed Tracer
Page Speed
YSlowBlaze.io
WebPageTestpcapperf
WebMetrics
Mobile Situation
Metrics•framerate•bytes transferred•caching•cookies•cache manifest•code size•execution speed
Network Variances2G, EDGE, 3G, 4G, LTE, ...
Continous Integration
“Too Many Phones Will Kill You...”
Stake Holders
Browser vendors
Web Site Developers
Application Developers
ServiceProvider
Approaches
Inject instrumentation
Read the source code
Proxy
High-speed Camera
Intrusive Emulation Observation
Benchmark
RF Monitor
Remote inspection
Strategies
1 Replicate and/or analyze on desktop
2 Tweak and insert instrumentation
Reducing complexity
System level
Caveats
Concept
Focus
Tools of Trade
Nexus One Gingerbread
http://source.android.com/source/building-devices.html
Headless WebKit
http://www.phantomjs.org https://github.com/ariya/phantomjs
“Full web stack.No browser required”
Source Code
WebKit
V8 http://code.google.com/p/v8/
http://www.webkit.org/
http://android.git.kernel.org/?p=platform/external/webkit.git
http://opensource.apple.com/
Di!erent WebKit “Ports”WebCore graphics
MaciOS
ChromiumAndroid Qt Gtk
CoreGraphics
Skia
QPainter
Cairo
graphics stack
GraphicsContext
Network
“Understanding Mobile Web Browser Performance”Rajiv Vijayakumar (Qualcomm)
Wed 2:40 pm, Ballroom ABCD
Web Inspector Network
HTTP Archive (HAR)
http://www.softwareishard.com/blog/har-12-spec/
Automating Network Sni"ng (Desktop)
phantomjs netsniff.js http://m.bing.com
Visualize using online HAR viewer
Android WebKit + Network Stack
WebView
libwebcore
Java
C++
Browser
Java
JNI
Network Stack Java
Real-time Sni"ng + Postprocessing
waiting data transfer
WebCoreResourceLoader::Finished()
WebCoreResourceLoader::AddData(...)WebFrame::startLoadingResource
06-12 22:57:48.430 D/webcoreglue( 1357): startLoadingResource NETWORK 0x66d368 http://en.m.wikipedia.org/wiki/Orchid06-12 22:57:48.710 D/webcoreglue( 1357): ReceivedResponse NETWORK handle=0x66d368 mimeType=text/html url=http://en.m.wikipedia.org/wiki/Orchid06-12 22:57:48.780 D/webcoreglue( 1357): startLoadingResource NETWORK 0x6a8678 http://en.m.wikipedia.org/stylesheets/android.css06-12 22:57:48.780 D/webcoreglue( 1357): startLoadingResource NETWORK 0x6ab388 http://en.m.wikipedia.org/javascripts/jquery.js06-12 22:57:48.790 D/webcoreglue( 1357): startLoadingResource NETWORK 0x6ab7e8 http://en.m.wikipedia.org/javascripts/application.js06-12 22:57:48.790 D/webcoreglue( 1357): AddData NETWORK 0x66d368 4162 http://en.m.wikipedia.org/wiki/Orchid06-12 22:57:48.790 D/webcoreglue( 1357): AddData NETWORK 0x66d368 8192 http://en.m.wikipedia.org/wiki/Orchid06-12 22:57:48.790 D/webcoreglue( 1357): AddData NETWORK 0x66d368 1361 http://en.m.wikipedia.org/wiki/Orchid06-12 22:57:48.980 D/webcoreglue( 1357): AddData NETWORK 0x66d368 8192 http://en.m.wikipedia.org/wiki/Orchid06-12 22:57:48.980 D/webcoreglue( 1357): AddData NETWORK 0x66d368 803 http://en.m.wikipedia.org/wiki/Orchid06-12 22:57:49.000 D/webcoreglue( 1357): AddData NETWORK 0x66d368 4702 http://en.m.wikipedia.org/wiki/Orchid06-12 22:57:49.000 D/webcoreglue( 1357): AddData NETWORK 0x66d368 4507 http://en.m.wikipedia.org/wiki/Orchid06-12 22:57:49.020 D/webcoreglue( 1357): AddData NETWORK 0x66d368 8192 http://en.m.wikipedia.org/wiki/Orchid06-12 22:57:49.050 D/webcoreglue( 1357): AddData NETWORK 0x66d368 6750 http://en.m.wikipedia.org/wiki/Orchid
Example: Orchidadb logcat -v time | grep NETWORK
Example: Orchid
Going O#ine: Cache Manifest
https://github.com/jamesgpearce/confess
phantomjs confess.js http://functionsource.com
Automatic localstorage optimization
Graphics
Drawing Command Analysis
GraphicsContext
WebCore graphics
Skia
Log file
Example: BingplatformInitsavePlatformStatetranslate 0,0translate 0,0clip 1,0 0x6.95322e-310fillRect 0,0 800x556 color ff ff ff ffrestorePlatformStateplatformDestroyplatformInitsavePlatformStatetranslate 0,0translate 0,0clip 1,0 0x6.95322e-310fillRect 0,0 800x556 color ff ff ff ffrestorePlatformStateplatformDestroyplatformInitsavePlatformStatetranslate 0,0translate 0,0clip 1,0 0x6.95322e-310fillRect 0,0 800x556 color ff ff ff fffillRect 0,0 800x556 color ff ff ff ff
Painting Traces
Display List Approach
GraphicsContext
WebKit
Skia
“SkPicture”
no overhead anymore
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
16:24:04.070 D/webcoreglue( 273): drawContent 11 ms16:24:04.110 D/webcoreglue( 273): drawContent 13 ms16:24:04.150 D/webcoreglue( 273): drawContent 13 ms16:24:04.190 D/webcoreglue( 273): drawContent 10 ms16:24:04.240 D/webcoreglue( 273): drawContent 10 ms16:24:04.280 D/webcoreglue( 273): drawContent 13 ms16:24:04.320 D/webcoreglue( 273): drawContent 13 ms16:24:04.360 D/webcoreglue( 273): drawContent 13 ms16:24:06.080 D/webcoreglue( 273): drawContent 12 ms16:24:06.140 D/webcoreglue( 273): drawContent 10 ms16:24:06.180 D/webcoreglue( 273): drawContent 13 ms16:24:06.230 D/webcoreglue( 273): drawContent 14 ms16:24:06.600 D/webcoreglue( 273): drawContent 26 ms16:24:06.640 D/webcoreglue( 273): drawContent 13 ms16:24:06.860 D/webcoreglue( 273): drawContent 33 ms16:24:06.890 D/webcoreglue( 273): drawContent 12 ms16:24:06.930 D/webcoreglue( 273): drawContent 13 ms16:24:06.960 D/webcoreglue( 273): drawContent 13 ms16:24:07.000 D/webcoreglue( 273): drawContent 13 ms
adb logcat -v time | grep drawContent
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
https://github.com/ariya/X2 network/netspiegel
Proxy
Intertubes
port 8080SQLite DB
Mirror
port 8081
JavaScript
Remote Console
http://github.com/senchalabs/android-tools
http://www.sencha.com/blog/remote-javascript-debugging-on-android/
Garbage Collectorbool 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
06-13 13:24:36.470 D/v8 ( 532): PerformGarbageCollection 2006-13 13:24:36.630 D/v8 ( 532): PerformGarbageCollection 3278806-13 13:24:36.740 D/v8 ( 532): PerformGarbageCollection 11606-13 13:24:36.810 D/v8 ( 532): PerformGarbageCollection 8806-13 13:24:36.870 D/v8 ( 532): PerformGarbageCollection 5206-13 13:24:37.000 D/v8 ( 532): PerformGarbageCollection 2006-13 13:24:37.090 D/v8 ( 532): PerformGarbageCollection 2406-13 13:24:37.450 D/v8 ( 532): PerformGarbageCollection 3588406-13 13:24:39.400 D/v8 ( 532): PerformGarbageCollection 2006-13 13:24:39.730 D/v8 ( 532): PerformGarbageCollection 3392
adb logcat -v time | grep GarbageCollection
Keyword vs Identifier
instanceof instanceComponent
requires checking 9 chars
a g h j k l m o p q x y z
Function Parsing
foobar = function(x, y, z){....}
foobar(x, y, z);
Analyze the syntaxMark the position of
function ‘foobar’
Compile and run the function ‘foobar’
Static Code Analysishammerjs --syntax source-file.js
https://github.com/senchalabs/hammerjs
JSON syntax tree
Reflect.parse(code)
Syntax Tree
Variable Declaration
IdentifierLiteral Constant
answer 42
var answer = 42;keyword equal sign
identifier number
"type": "IfStatement","test": { "type": "BinaryExpression", "operator": "==", "left": { "type": "Identifier", "name": "x" }, "right": { "type": "Identifier", "name": "y" } }, "consequent": { "type": "ExpressionStatement", "expression": { "type": "CallExpression", "callee": { "type": "Identifier", "name": "foo" }, "arguments": [] } }, "alternate": null
if (x == y) foo();
Danger!
Deploy-time Pruning
function createList(position, options) { ... some code ... }
createList({ x: 0, y: 0});createList({ x: 0, y: 100});
Never used
Avoid Object Construction
startTime = new Date();// heavy processingelapsed = (new Date()) - startTime;
startTime = Date.now();// heavy processingelapsed = Date.now() - startTime;
Create + Destroy
Irrelevant Platforms
if (typeof object.attachEvent !== 'undefined') { // Internet Explorer < 9 object.attachEvent('on'+ev, createWrapper(func));} else { // DOM Level 3 object.addEventListener(ev, func);}
Does not apply in Mobile
User Interactions
Event Recorder & Player
http://www.sencha.com/blog/event-recorder-for-android-web-applications/
Conclusion
Today
Replicate and analyze on desktop
Find, look at, and understand the source code
Tweak at the system level + post-processing
Future
More built-in instrumentation
Remote inspection
API for test automation