Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Chrome DevTools for rendering measurement for HTML5 graphics

I would like to measure the performance between canvas and svg in HTML5.

I have done so far. I have created multiple circles in svg and canvas. Both have a 500 x 500 Element width and height.

I found out I am measuring the scripting time. If I use the dev tools in Chrome, the scripting time is nearly equal to my measured time. Now, how can I measure the rendering time? Would be a code with separate canvas and svg circle creation and devtools for rendering a good way to compare svg and canvas rendering performance?

<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

Somehow the scripting time and my measured performance time is different. Can someone tell me if this performance comparison is useful?

I did the test multiple times, the performance time is always different but canvas is faster than svg in rendering and also in scripting.

Why in rendering? Scripting should be because of the DOM reference of svg?

This test I did with seperate svg and canvas, I just rendered first only svg, and in the next test only canvas.

like image 377
Khan Avatar asked Mar 01 '17 14:03

Khan


People also ask

How do I enable Rendering in Chrome?

# Open the Rendering tabPress Command + Shift + P (Mac) or Control + Shift + P (Windows, Linux, ChromeOS) to open the Command Menu. Start typing rendering , select Show Rendering, and press Enter . DevTools displays the Rendering tab at the bottom of your DevTools window.

How do I use Performance Monitor in Chrome?

To access the Performance tab, navigate to the website you want to profile, then open Chrome DevTools by right-clicking and selecting Inspect. Select the Performance tab inside Chrome DevTools. The easiest way to capture a performance profile is by clicking the Start profiling and reload page icon.

Which method in Chrome is used to test a web page performance?

In Chrome you can access the Task Manager from the Window menu. This is a simple way to check a web page's requirements. Chrome's Task Manager — watch out for memory and CPU hogs!

Where is the Devices tab for simulating mobile devices?

If there is a need to add a new mobile resolution to a predefined list, we can simply do that in Developers Tool Menu (F11) > Devices tab. On this tab we can enable/disable existing devices or add a new one.


1 Answers

The problem with SVG.

Below is a performance test of drawing a big circle on a canvas and a SVG image.

Both get about the same performance 30ms per circle on my machine and chrome.

Run the test and see the result. If you watch the progress you may notice that it begins to slow down a little. When the first test is run click the button again and this time you will notice that there is even more of a slow down.

Do a 3rd test and slower still, but the performance per circle for both canvas and SVG has not changed, where is the slow down coming from.

The DOM is not javascript.

The code run to add a node to the SVG does not care how many nodes the SVG has, but when add nodes to the SVG image and your code exits you have informed the DOM that your SVG element is dirty and needs to be redrawn.

I grouped the test into groups of ~10 before exiting. This means that for every ten circles added the DOM will redraw all the SVG nodes from scratch and outside the javascript context and your ability to measure or control it.

When you click test the second time the SVG already has 10000 circles, so after adding the first ten the DOM happily re-renders 10000+10 circles.

It is next to impossible to get an accurate measure of SVG performance.

Using timeline

I ran the code snippet below with timeline recording. I ran the test two times.

The next two images show the same period. The top one is at the start of the test and the next one is at the end of the second test.

I have mark the GPU sections that are likely involved in rendering the SVG. Note how they change from trivial to excessive.

enter image description here

enter image description here

This image shows one cycle of the test 10 renders in the second test cycle. The code execution is barely visible at ~1ms but the GPU is flat out with a huge 175ms devoted to drawing all the SVG circle again.

enter image description here

When you use SVG you must remember that when you make a change to it the DOM will re-render all of it. It does not care if it's visible or not. If you change the size it's redrawn.

To use SVG you must bundle all your calls into one execution context to get the best performance.

Canvas V SVG

Both SVG and Canvas use the GPU with very similar shaders to do the work. Drawing a circle in SVG or Canvas takes the same time. The advantage that the canvas has over SVG is that you control the rendering, what when and where. For SVG you only control content and have little say over rendering.

    
    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);
    #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" 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>
like image 63
Blindman67 Avatar answered Oct 18 '22 15:10

Blindman67