使用 Chrome DevTools 对 HTML5 图形进行渲染测量

Posted

技术标签:

【中文标题】使用 Chrome DevTools 对 HTML5 图形进行渲染测量【英文标题】:Use Chrome DevTools for rendering measurement for HTML5 graphics 【发布时间】:2017-07-20 22:44:19 【问题描述】:

我想测量 html5 中 canvas 和 svg 之间的性能。

到目前为止,我已经做到了。我在 svg 和画布中创建了多个圆圈。 两者的元素宽度和高度均为 500 x 500。

我发现我正在测量脚本编写时间。如果我使用 Chrome 中的开发工具,脚本编写时间几乎等于我测量的时间。 现在,我如何测量渲染时间?将是具有单独画布和 svg 圆创建和 devtools 的代码,用于渲染比较 svg 和画布渲染性能的好方法?

<html>
    <head>
        <script type="text/javascript">
            var svgNS = "http://www.w3.org/2000/svg";
            function createCircle1() 
                var t3 = performance.now();
                for (var x = 1; x <= 1000; x++) 
                    for (var y = 1; y <= 100; y++) 
                        var c = document.getElementById("myCanvas");
                        var ctx = c.getContext("2d");
                        ctx.beginPath();
                        ctx.arc(x, y, 5, 0, 2 * Math.PI);
                        ctx.stroke();

                    
                
                var t4 = performance.now();

                console.log("canvas time " + (t4 - t3) + " milliseconds.")

                var t0 = performance.now();
                for (var x = 1; x <= 1000; x++) 
                    for (var y = 1; y <= 100; y++) 
                        var myCircle = document.createElementNS(svgNS, "circle"); //to create a circle, for rectangle use rectangle
                        myCircle.setAttributeNS(null, "cx", x);
                        myCircle.setAttributeNS(null, "cy", y);
                        myCircle.setAttributeNS(null, "r", 5);
                        myCircle.setAttributeNS(null, "stroke", "none");
                        document.getElementById("mySVG").appendChild(myCircle);
                    
                
                var t1 = performance.now();

                console.log("svg time " + (t1 - t0) + " milliseconds.")
            
        </script>
    </head>
    <body onload="createCircle1();">
        <svg id="mySVG"   style="border:1px solid #d3d3d3;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg>
        <canvas id="myCanvas"   style="border:1px solid #d3d3d3;"></canvas>
    </body>
</html>

不知何故,脚本编写时间和我测量的性能时间不同。 谁能告诉我这种性能比较是否有用?

我进行了多次测试,性能时间总是不同,但画布在渲染和脚本方面都比 svg 快。

为什么在渲染中?脚本应该是因为svg的DOM引用吧?

我用单独的 svg 和画布进行了这个测试,我只是先渲染了 svg,然后在下一个测试中只渲染了画布。

【问题讨论】:

【参考方案1】:

SVG 的问题。

以下是在画布上绘制大圆圈和 SVG 图像的性能测试。

在我的机器和 chrome 上,每圈 30 毫秒的性能都差不多。

运行测试并查看结果。如果您观察进度,您可能会注意到它开始放慢一点。运行第一个测试时,再次单击该按钮,这一次您会注意到速度变慢了。

进行第 3 次测试,速度仍然较慢,但画布和 SVG 的每圈性能没有改变,慢是从哪里来的。

DOM 不是 javascript。

向 SVG 添加节点的代码并不关心 SVG 有多少节点,但是当向 SVG 图像添加节点并且您的代码退出时,您已经通知 DOM 您的 SVG 元素是脏的并且需要重绘。

在退出之前,我将测试分成了大约 10 组。这意味着每添加 10 个圆圈,DOM 就会从头开始重绘所有 SVG 节点,并在 javascript 上下文以及您测量或控制它的能力之外。

当您第二次单击测试时,SVG 已经有 10000 个圆圈,所以在添加前十个之后,DOM 会愉快地重新渲染 10000+10 个圆圈。

要准确衡量 SVG 性能几乎是不可能的。

使用时间轴

我用时间线记录运行了下面的代码 sn-p。我跑了两次测试。

接下来的两张图片显示的是同一时期。第一个是在测试开始时,下一个是在第二个测试结束时。

我已经标记了可能涉及渲染 SVG 的 GPU 部分。请注意它们如何从琐碎变为过度。

此图显示了在第二个测试周期中的一个测试周期 10 渲染。代码执行在大约 1 毫秒时几乎看不到,但 GPU 用了 175 毫秒的巨大时间来再次绘制所有 SVG 圆圈。

当您使用 SVG 时,您必须记住,当您对其进行更改时,DOM 将重新渲染所有内容。它不关心它是否可见。如果你改变它的大小,它会重绘。

要使用 SVG,您必须将所有调用捆绑到一个执行上下文中以获得最佳性能。

画布 V SVG

SVG 和 Canvas 都使用带有非常相似着色器的 GPU 来完成工作。在 SVG 或 Canvas 中绘制圆需要相同的时间。画布相对于 SVG 的优势在于您可以控制渲染、何时何地渲染。对于 SVG,您只能控制内容,而对渲染几乎没有发言权。

    
    var running = false;
    var test = function()
        if(running)
           return;
        
        var mySVG = document.getElementById("mySVG");
        var myCanvas = document.getElementById("myCanvas");
        var ctx = myCanvas.getContext("2d");
        var myCircle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
        running = true;
        const testCount = 1000;
        const groupCount = 10;
        var times = [[],[]];     
        var names =["Canvas test.","SVG test."];
        var indexs = [0,0];
        var tests = [function()  
            now = performance.now();
            ctx.beginPath();
            ctx.arc(250, 250, 250, 0, 2 * Math.PI);
            ctx.fill();
            return performance.now()-now;
        ,
        function()  
            now = performance.now();
            var circle = myCircle.cloneNode(); 
            circle.setAttributeNS(null, "cx", 250);
            circle.setAttributeNS(null, "cy", 250);
            circle.setAttributeNS(null, "r", 250);
            circle.setAttributeNS(null, "stroke", "none");
            mySVG.appendChild(circle);
            return performance.now()-now;
        ];
        for(var i = 0; i < testCount; i ++)  // preallocate and zeor arrays
            times[0][i] = 0;
            times[1][i] = 0;
        
        var testComplete = false;
        function doTests()
            for(i = 0; i < groupCount; i ++)
                var testIndex = Math.floor(Math.random()*2);
                times[testIndex][indexs[testIndex]] = tests[testIndex]();
                indexs[testIndex] += 1;
                if(indexs[testIndex] >= testCount)
                     testComplete = true;
                     return;
                            
            
        
        function getResults()
            // get the mean
            var meanA = 0;
            var meanB = 0;
            var varianceA = 0;
            var varianceB = 0;
            var totalA = 0;
            var totalB = 0;
            for(var i = 0; i < testCount; i ++)  // preallocate and zero arrays
                totalA += i < indexs[0] ? times[0][i] : 0;
                totalB += i < indexs[1] ? times[1][i] : 0;
            
            meanA = Math.floor((totalA / indexs[0]) * 1000) / 1000;
            meanB = Math.floor((totalB / indexs[1]) * 1000) / 1000;

            for(var i = 0; i < testCount; i ++)  // preallocate and zero arrays
                varianceA += i < indexs[0] ? Math.pow((times[0][i] - meanA),2) : 0;
                varianceB += i < indexs[1] ? Math.pow((times[1][i] - meanB),2) : 0;
            
            varianceA = Math.floor((varianceA / indexs[0]) * 1000) / 1000;
            varianceB = Math.floor((varianceB / indexs[1]) * 1000) / 1000;
            result1.textContent = `Test $names[0] Mean : $meanAms Variance : $varianceAms Total : $totalA.toFixed(3)ms over $indexs[0] tests.`;
            result2.textContent = `Test $names[1]. Mean : $meanBms Variance : $varianceBms Total : $totalB.toFixed(3)ms over $indexs[1] tests.`;

         
         
         function test()
             doTests();
             var p = Math.floor((((indexs[0] + indexs[1]) /2)/ testCount) * 100);
             if(testComplete)
                 getResults();
                 p = 100;
                 running = false;
             else
                 setTimeout(test,10);
             
             progress.textContent = p+"%";
          
         
          test()
    

    startBut.addEventListener("click",test);
    #ui 
      font-family : Arial;
    
    <div id="ui">
        <h3>Comparative performance test</h3>
        Adding circles to canvas V adding circles to SVG.<br> The test adds 1000 * 10 circles to the canvas or SVG with as much optimisation as possible and to be fair.<br>
        <input id="startBut" type="button" value = "Start test"/>
        <div id="progress"></div>
        <div id="result1"></div>
        <div id="result2"></div>
        <h3>SVG element</h3>
        <svg id="mySVG"   style="border:1px solid #d3d3d3;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg>
        <h3>Canvas element</h3>
        <canvas id="myCanvas"   style="border:1px solid #d3d3d3;"></canvas>
     </div>

【讨论】:

以上是关于使用 Chrome DevTools 对 HTML5 图形进行渲染测量的主要内容,如果未能解决你的问题,请参考以下文章

Chrome DevTools中的这些骚操作,你都知道吗?

在 Chrome Devtools 中检测和观察对样式表所做的更改

Chrome DevTools 触摸仿真不起作用

你未必知道的12个Chrome DevTools使用技巧

在 Chrome DevTools 中搜索 HTML 元素

馃専 Chrome DevTools 涓冨ぇ鏂板姛鑳?/a>