使用 V8 的内部分析器优化 web 应用

Profile your web application with V8’s internal profiler

原文 : https://developers.google.com/v8/profiler_example

Today's highly optimized virtual machines can run web apps at blazing speed. But one shouldn't rely only on them to achieve great performances: a carefully optimized algorithm or a less expensive function can often reach many-fold speed improvements on all browsers. Chrome Developer Tool’s CPU Profiler helps you analyze your code bottlenecks. But sometimes, you need to go deeper and more granular: this is where V8's internal profiler comes in handy.

如今高度优化的虚拟机可以让 Web 应用运行飞快, 但我们不应该依赖它来达到出众的性能. 仔细优化过的算法或开销更小的函数可以使得应用在任何浏览器下运行性能都成倍提高. 谷歌开发者工具中的 CPU 分析器可以帮我们分析代码中的瓶颈. 但有时我们可能需要更深入更细粒度的分析, 此时 V8 内部分析器就可以派上用场了.

Let’s use that profiler to examine the Mandelbrot explorer demo that Microsoft released together with IE10. After the demo release, V8 has fixed a bug that slowed down the computation unnecessarily (hence the poor performance of Chrome in the demo’s blog post) and further optimized the engine, implementing a faster exp() approximation than what the standard system libraries provide. Following these changes, the demo ran 8x faster than previously measured in Chrome.

But what if you want the code to run faster on all browsers? You should first understand what keeps your CPU busy. Run Chrome (Windows and Linux Canary) with the following command line switches, which will cause it to output profiler tick information (in the v8.log file) for the URL you specify, which in our case was a local version of the Mandelbrot demo without web workers:

我们来使用分析器来检验一下 Mandelbrot expolorer demo, 它是同微软的 IE10 一共发布的. 这个 demo 发布后, V8 修正了一个 bug, 它使得运算变慢(其实是不必要的), 并且对 V8 引擎做了更进一步的优化, 实现了比标准系统库更快的 exp() 近似计算. 随着这些优化, 该 demo 在新的 chrom 中的运行速度比以前快了 8 倍.

但如果你想让代码在所有浏览器上都运行的更快该怎么办呢? 你应该先找出是什么过度占用了 CPU. 添加以下参数并启动 chrome 将会输出打开的页面的分析器时间片信息. 我们在下面的例子中将打开一个 Mandelbrot demo 不带 web worker 的本地版本:

$ ./chrome --js-flags=”--prof” --no-sandbox http://localhost:8080/index.html

译注: 对于 node , 可以使用 node --prof index.js 来执行, 会在当前路径下生成 isoloate-xxxxx-v8.log 这样的文件

When preparing the test case, make sure it begins its work immediately upon load, and simply close Chrome when the computation is done (hit Alt+F4), so that you only have the ticks you care about in the log file. Also note that web workers aren’t yet profiled correctly with this technique.

Then, process the v8.log file with the tick-processor script that ships with V8 (or the new practical web version):

准备测试用例的时候需要注意, 要让程序在加载后立即开始执行, 计算结束后直接关闭 Chrome 即可, 这样可以使结果尽量准确. 另外需要注意, web work 目前还不能使用该方法得到正确的分析结果.
然后需要使用 v8 中自带的 tick-processor 脚本来处理一下 v8.log 文件. 或者可以使用 web 工具
2016-07-13 更新: 新版本(测试了4.4.3)的 node 可以用更简单的方式: node --prof-process isoloate-xxxxx-v8.log 即可生成分析结果.

$ v8/tools/linux-tick-processor v8.log

译注: node 源码中就有该脚本, 不依赖 GUI, 适合在服务器上直接使用. 解压 node 源码后, 路径 tools/v8-prof/tick-processor.js

Here’s an interesting snippet of the processed output that should catch your attention:

以下是经过 tick-processor 处理后的文件中我们需要特别留意的片段:

Statistical profiling result from null, (14306 ticks, 0 unaccounted, 0 excluded).
 [Shared libraries]:
   ticks  total  nonlib   name
   6326   44.2%    0.0%  /lib/x86_64-linux-gnu/libm-2.15.so
   3258   22.8%    0.0%  /.../chrome/src/out/Release/lib/libv8.so
   1411    9.9%    0.0%  /lib/x86_64-linux-gnu/libpthread-2.15.so
     27    0.2%    0.0%  /.../chrome/src/out/Release/lib/libwebkit.so

The top section shows that V8 is spending more time inside an OS-specific system library than in its own code. Let’s look at what’s responsible for it by examining the “bottom up” output section, where you can read indented lines as "was called by" (and lines starting with a * mean that the function has been optimized by Crankshaft):

上面的部分显示 V8 花在 OS 的系统 lib 中的运行时间比花在它自己实际的代码的时间要多. 我们可以通过 "bottom up" 部分查一下其背后的原因. "bottom up" 部分的内容具有缩进结构, 其表示上一行指示的代码是被下一行指示的代码所调用 ( 代码位置前多出的 * 表示该函数是被 V8 编译优化器优化过的 ) :

[Bottom up (heavy) profile]:
  Note: percentage shows a share of a particular caller in the total
  amount of its parent calls.
  Callers occupying less than 2.0% are not shown.

   ticks parent  name
   6326   44.2%  /lib/x86_64-linux-gnu/libm-2.15.so
   6325  100.0%    LazyCompile: *exp native math.js:91
   6314   99.8%      LazyCompile: *calculateMandelbrot http://localhost:8080/Demo.js:215

More than 44% of the total time is spent executing the exp() function inside a system library! Adding some overhead for calling system libraries, that means about two thirds of the overall time are spent evaluating Math.exp().

可以看出超过 44% 时间都用于执行系统 Lib 中的 exp() 函数! 算上调用操作系统的库的产生的额外开销, 总共有大约三分之二的运行时间都消耗在计算 Math.exp() 上面了.

If you look at the JavaScript code, you’ll see that exp() is used solely to produce a smooth grayscale palette. There are countless ways to produce a smooth grayscale palette, but let’s suppose you really really like exponential gradients. Here is where algorithmic optimization comes into play.

如果观察 Javascript 代码, 你会发现 exp() 被用来产生一个平滑的灰度渐变调色盘. 我们有很多产生它的方式, 但如果你确实一定要用它, 我们可以考虑用下面的算法来优化它.

You’ll notice that exp() is called with an argument in the range -4 < x < 0, so we can safely replace it with its Taylor approximation for that range, which will deliver the same smooth gradient with only a multiplication and a couple of divisions:

你也许注意到 exp() 的调用实参范围是 -4 < x < 0, 我们大可直接使用泰勒逼近这个范围, 这样我们只需要一个乘法和两个除法计算即可产生同样平滑的梯度:

exp(x) ≈ 1 / ( 1 - x + x*x / 2) for -4 < x < 0 

Tweaking the algorithm this way boosts the performance by an extra 30% compared to latest Canary and 5x to the system library based Math.exp() on Chrome Canary.

用这种算法进行优化后, 其性能比最新的 Canary 版本浏览器快 30% 左右, 比调用系统库快5倍

[图片上传失败...(image-cbcb00-1580524209223)]

This example shows how V8’s internal profiler can help you go deeper into understanding your code bottlenecks, and that a smarter algorithm can push performance even further.

To compare VM performances that represents today’s complex and demanding web applications, one might also want to consider a more comprehensive set of benchmarks such as the Octane Javascript Benchmark Suite.

这个例子为我们揭示了 V8 内部分析器如何帮我们从更深的层次去理解我们代码中的瓶颈, 也为我们展示了更好的算法是如何提高性能的.
对比两个代表当今 Web 应用的复杂性和需求的程序在 VM 中执行的性能, 我们可能还需要参考更加全面的基准测试系统, 比如Octane Javascript 基准测试套件.

Google 原文更新于 二月 26, 2015

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,050评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,538评论 1 306
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,673评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,622评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,047评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,974评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,129评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,893评论 0 209
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,654评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,828评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,297评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,619评论 3 262
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,326评论 3 243
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,176评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,975评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,118评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,909评论 2 278

推荐阅读更多精彩内容