2

我正在为 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);
        }
    }
 })();

我的问题是:如何以编程方式测量画布动画的性能?

4

3 回答 3

2

由于 phantomjs 似乎无法在任何动画上产生超过 3-4 FPS,我最终使用“真实”浏览器来完成这项任务。由于 Chrome 的远程调试协议,我能够自动化它。

我制作了一个 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;
    }
};
于 2013-10-18T07:59:20.360 回答
2

几个月前我写了一个小脚本来专门测量 FPS 和requestAnimationFrame.

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

仪表快照

用法很简单:

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

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

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

示例

var meter = new animMeter('divElementId');

function animate(timeArg) {

    /// funky stuff here

    meter.update(timeArg);

    requestAnimationFrame(animate);
}

可以在此处找到此操作的演示

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

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

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

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

于 2013-10-01T22:07:21.100 回答
0

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

于 2013-10-01T19:48:48.210 回答