我想在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>
不知何故,脚本编写时间和我测量的执行时间是不同的。 有人能告诉我这种性能比较是否有用?
我多次进行测试,性能时间总是不同,但画布在渲染和脚本编写方面比svg更快。
为什么渲染?脚本应该是因为svg的DOM引用?
我用单独的svg和canvas做过这个测试,我只是首先渲染了svg,而在下一个测试中只用了画布。
答案 0 :(得分:8)
下面是在画布上绘制一个大圆圈和SVG图像的性能测试。
在我的机器和chrome上,每个圆圈的性能都达到相同的30ms。
运行测试并查看结果。如果您观察进度,您可能会注意到它开始减慢一点。当第一次测试运行时,再次单击该按钮,这次您会注意到更慢的速度。
进行第3次测试并且速度更慢,但是canvas和SVG的每个圆圈的性能没有改变,减速来自何处。
运行以向SVG添加节点的代码并不关心SVG有多少节点,但是当向SVG图像添加节点并且您的代码退出时,您已通知DOM您的SVG元素是脏的并且需要是重绘。
我在退出前将测试分组为~10组。这意味着,对于每十个添加的圈子,DOM将从头开始重绘所有SVG节点,并在javascript上下文之外,以及您测量或控制它的能力。
当你第二次点击测试SVG已经有10000个圆圈时,所以在添加前十个之后,DOM会愉快地重新渲染10000 + 10个圆圈。
几乎不可能准确衡量SVG性能。
我使用时间轴录制运行下面的代码段。我跑了两次测试。
接下来的两张图片显示的是同一时期。最上面一个是在测试开始时,下一个是在第二个测试结束时。
我已经标记了可能涉及渲染SVG的GPU部分。注意他们如何从琐碎变为过度。
此图显示了测试10在第二个测试周期中呈现的一个周期。代码执行在~1ms时几乎看不到,但是GPU很平坦,只有175ms用于再次绘制所有SVG圈。
当您使用SVG时,您必须记住,当您对其进行更改时,DOM将重新呈现所有内容。它不关心它是否可见。如果您更改了它重绘的大小。
要使用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 : ${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;