以编程方式测量画布动画的性能

时间:2013-10-01 16:00:44

标签: javascript performance canvas phantomjs requestanimationframe

我正在构建一个JavaScript性能竞赛的测试平台。其中一项任务是挑战参赛者优化负责处理画布动画的JavaScript代码。提交解决方案后,服务器使用PhantomJS运行它,并在动画播放20秒后读取平均FPS数。问题是我为优化和未优化的代码获得了3-4FPS。这使得无法判断代码是否得到了改进。

一些事实:

  • 我100%确定phanotmjs正确渲染动画(完成几个截图)
  • 在浏览器中未经优化的代码以13FPS运行,优化运行在58FPS
  • phantomjs不支持requestAnimationFrame所以我不得不使用polyfill
  • 我正在使用下面的代码来测试FPS的数量

frameCounter.js

 var frameCounter = (function() {
    var frames = 0;
    var startTime = new Date();

    function bump() {
        frames++;
        window.requestAnimationFrame(bump);
    }

    bump();

    return {
        getFPS: function() {
            var time = (new Date() - startTime) / 1000;

            return (frames/time).toPrecision(4);
        }
    }
 })();

我的问题是:如何以编程方式衡量画布动画的效果?

3 个答案:

答案 0 :(得分:3)

几个月前我写了一个小脚本专门测量requestAnimationFrame的FPS和消费量。

我不确定它会帮助你100%,但它可以给你一个很好的指针。

Meter snap

用法非常简单:

  • 在循环之前的代码中的某处初始化仪表,您可以在其中指定要用作仪表的div元素
  • 确保你获取requestAnimationFrame给出的参数,因为这将告诉我花了多少时间(如果没有,它将回退到使用日期/时间方法)。
  • 使用此参数对其方法进行简单调用。

绿色表示您在最佳FPS范围内运行(大多数情况下为60)。黄色表示循环消耗超过大约16.7毫秒,速率降低到大约一半。橙色意味着您使用的预算是预算的两倍以上。

仪表使用加权FPS为您提供更准确的测量。

示例

var meter = new animMeter('divElementId');

function animate(timeArg) {

    /// funky stuff here

    meter.update(timeArg);

    requestAnimationFrame(animate);
}

<强> A demo of this in action can be found here

您可以在预先最小化的底部找到仪表本身的代码。随意复制和粘贴。它附带MIT许可证。

和使用这样的仪表一样:它们自己会花费几毫秒的时间来更新图形,从而引入微小的误差范围。

另一件需要注意的事情是,rAF将始终试图达到60 FPS,因此仪表永远不会测量比这更高的帧速率。

如果您需要测量更高的帧速率,您可以不带参数调用更新方法并使用setTimeout而不是rAF,它将使用日期/时间来衡量性能 - 稍微更不准确但您可以获得更高FPS数字(这是任意帧,因为显示器无法显示比同步时更多的帧...通常为60 fps)。

答案 1 :(得分:2)

由于幻影似乎无法在任何动画上产生超过3-4 FPS,我最终使用了真实的&#39;这个任务的浏览器。由于Chrome remote debugging protocol,我能够实现自动化。

我创建了一个node.js应用程序,每次有新的代码要测试时,都会执行以下步骤:

  • 已连接到Chrome浏览器中的标签页(浏览器必须以--remote-debugging-port=9222标志运行)
  • 导航标签到测试页
  • 评估了试图尽可能快地渲染300帧动画的标签内的代码
  • 返回执行时间

以下是我的代码中的代码段:

//connect to a tab (you can find <tab-debug-id> on http://localhost:9222/json page)
var ws = new WebSocket("ws://localhost:9222/devtools/page/<tab-debug-id>");

ws.onerror = function() {
  //handle error
};

ws.onopen = function()
{
    //when connection is opened hard reload the page before we start
    ws.send(JSON.stringify({
        id: 1,
        method: "Page.reload",
        params: {
            ignoreCache: true
        }
    }));
};

ws.onmessage = function (evt)
{
    var data = JSON.parse(evt.data);

    if(data.id === 1) {
        //reload was successful - inject the test script
        setTimeout(function(){
           ws.send(JSON.stringify({
              id: 2,
              method: "Runtime.evaluate",
              params: {
                expression: '(' + injectedCode.toString() + '());'
              }
           }));
        }, 1000);
    } else if(data.id === 2) {
        //animation has finished - extract the result
        var result = data.result.result.value;
    }
};

答案 2 :(得分:0)

你可以使用Date.now()来减少对象创建浪费的时间,它应该至少提高一点精度