使用Chrome DevTools渲染HTML5图形的测量值

时间:2017-03-01 14:39:18

标签: javascript css html5 canvas svg

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

到目前为止我已经完成了。我在svg和canvas中创建了多个圆圈。 两者都具有500 x 500的元素宽度和高度。

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

<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" width="500" height="500" style="border:1px solid #d3d3d3;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg>
        <canvas id="myCanvas" width="500" height="500" style="border:1px solid #d3d3d3;"></canvas>
    </body>
</html>

This is the result of my code enter image description here

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

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

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

我用单独的svg和canvas做过这个测试,我只是首先渲染了svg,而在下一个测试中只用了画布。

1 个答案:

答案 0 :(得分:8)

SVG的问题。

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

在我的机器和chrome上,每个圆圈的性能都达到相同的30ms。

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

进行第3次测试并且速度更慢,但是canvas和SVG的每个圆圈的性能没有改变,减速来自何处。

DOM不是javascript。

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

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

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

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

使用时间轴

我使用时间轴录制运行下面的代码段。我跑了两次测试。

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

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

enter image description here

enter image description here

此图显示了测试10在第二个测试周期中呈现的一个周期。代码执行在~1ms时几乎看不到,但是GPU很平坦,只有175ms用于再次绘制所有SVG圈。

enter image description here

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

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

Canvas V SVG

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

&#13;
&#13;
    
    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 : ${meanA}ms Variance : ${varianceA}ms Total : ${totalA.toFixed(3)}ms over ${indexs[0]} tests.`;
            result2.textContent = `Test ${names[1]}. Mean : ${meanB}ms Variance : ${varianceB}ms 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);
&#13;
    #ui {
      font-family : Arial;
    }
&#13;
    <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" width="500" height="500" 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" width="500" height="500" style="border:1px solid #d3d3d3;"></canvas>
     </div>
&#13;
&#13;
&#13;