{"id":190,"date":"2015-02-10T11:01:37","date_gmt":"2015-02-10T16:01:37","guid":{"rendered":"https:\/\/blogs.mathworks.com\/graphics\/?p=190"},"modified":"2015-02-10T11:01:37","modified_gmt":"2015-02-10T16:01:37","slug":"area-scaling","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/graphics\/2015\/02\/10\/area-scaling\/","title":{"rendered":"Area Scaling"},"content":{"rendered":"<div class=\"content\"><p><a href=\"https:\/\/blogs.mathworks.com\/graphics\/2015\/01\/20\/performance-scaling\/\">Last time<\/a> we looked at how the performance of MATLAB's graphics system scales with the number of data points. Another interesting lens to look at performance scaling with is the way that performance scales with the number of pixels. This can actually show us a lot of interesting details of the balance of the compute and memory systems of our graphics card.<\/p><p>When we look at performance scaling through this lens, we'll keep coming up with charts that look something like this:<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/renderlimit.png\" alt=\"\"> <\/p><p>In this chart, the X axis is the size of the object we're drawing in pixels, and the Y axis is the number of objects we can draw per second. As you can see, I've sketched two curves on the chart. The one labeled \"Pixel Limit\" is a hyperbola which represents a constant number of pixels per second. The other curve is a horizontal line which I've labeled \"Geometry Limit\". These are also known as the \"fill rate\" and \"setup rate\". To a first order approximation, the \"pixel limit\" is a function of the details of the graphics card's memory system, and the \"geometry limit\" is a function of the graphics card's GPU. When we measure performance, we'll find that we always get numbers that are somewhere in the green shaded area. It isn't possible to cross over those two curves. In fact, as we'll see, it is usually pretty hard to get results up in that corner where the two curves meet. Real, measured data usually rounds off the corner between these two curves.<\/p><p>So let's collect some measurements and see how real data compares to this sketch. The following chunk of code creates 2,500 triangles and spins them around for 150 frames. It spins them using the hgtransform technique I described <a href=\"https:\/\/blogs.mathworks.com\/graphics\/2014\/10\/28\/makingthingsmove\/\">in this post<\/a>.<\/p><pre class=\"codeinput\">ntri = 2500;\r\nnframe = 150;\r\nradii = linspace(0,1,75);\r\nareas = (171.5*radii).^2 * 3 * sqrt(3) \/ 4;\r\nseconds = zeros(1,length(radii));\r\n<span class=\"keyword\">for<\/span> j=1:length(radii)\r\n    rad = radii(j);\r\n    cla\r\n    axis <span class=\"string\">square<\/span>\r\n    axis <span class=\"string\">off<\/span>\r\n    xlim([-1 1])\r\n    ylim([-1 1])\r\n    g = hgtransform;\r\n    theta = linspace(0,2*pi,ntri);\r\n    v = [rad*cos(theta)', rad*sin(theta)'];\r\n    x = 1:ntri;\r\n    o1 = floor(ntri\/3);\r\n    o2 = floor(2*ntri\/3);\r\n    f = [x', 1+mod(x+o1,ntri)', 1+mod(x+o2,ntri)'];\r\n    h = patch(<span class=\"string\">'Faces'<\/span>,f,<span class=\"string\">'Vertices'<\/span>,v,<span class=\"string\">'FaceVertexCData'<\/span>,x', <span class=\"keyword\">...<\/span>\r\n              <span class=\"string\">'FaceColor'<\/span>,<span class=\"string\">'flat'<\/span>,<span class=\"string\">'EdgeColor'<\/span>,<span class=\"string\">'none'<\/span>, <span class=\"keyword\">...<\/span>\r\n              <span class=\"string\">'Parent'<\/span>,g);\r\n    drawnow\r\n    t = nan(1,nframe);\r\n    rotmat = makehgtform(<span class=\"string\">'zrotate'<\/span>,pi\/20);\r\n    <span class=\"keyword\">for<\/span> k=1:nframe\r\n        tic\r\n        set(g,<span class=\"string\">'Matrix'<\/span>,get(g,<span class=\"string\">'Matrix'<\/span>) * rotmat);\r\n        drawnow\r\n        t(k) = toc;\r\n        <span class=\"keyword\">if<\/span> sum(t(1:k)) &gt; 1.5\r\n            <span class=\"keyword\">break<\/span>\r\n        <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">end<\/span>\r\n    seconds(j) = median(t(isfinite(t)));\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/areascaling_01.png\" alt=\"\"> <p>Now we can plot these results like so:<\/p><pre class=\"codeinput\">plot(areas,ntri.\/seconds)\r\nxlabel(<span class=\"string\">'Pixels per triangle'<\/span>)\r\nylabel(<span class=\"string\">'Triangles per second'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/areascaling_02.png\" alt=\"\"> <p>That looks kind of like the curve I sketched, but with a lot of noise for the small triangles. To make things clearer, lets add a \"hyperbolic grid\" with the following function:<\/p><pre class=\"language-matlab\"><span class=\"keyword\">function<\/span> hyperbolicgrid\r\n  radii = linspace(0,1,75);\r\n  areas = (171.5*radii).^2 * 3 * sqrt(3) \/ 4;\r\n  <span class=\"keyword\">for<\/span> j=1:8\r\n    line(areas,j*1e9.\/areas,<span class=\"string\">'Color'<\/span>,[.875 .875 .875], <span class=\"keyword\">...<\/span>\r\n         <span class=\"string\">'HandleVisibility'<\/span>,<span class=\"string\">'off'<\/span>)\r\n  <span class=\"keyword\">end<\/span>\r\n<\/pre><pre class=\"codeinput\">cla\r\nhold <span class=\"string\">on<\/span>\r\nhyperbolicgrid\r\nplot(areas,ntri.\/seconds)\r\nxlabel(<span class=\"string\">'Pixels per triangle'<\/span>)\r\nylabel(<span class=\"string\">'Triangles per second'<\/span>)\r\nxlim([0 inf])\r\nylim([0 5e5])\r\ntitle(<span class=\"string\">'Performance Scaling'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/areascaling_03.png\" alt=\"\"> <p>Now we can see that the curve doesn't actually follow one of the hyperbolas. The fill rate for small triangles is actually quite a bit lower than the fill rate for large triangles. This is something that you'll often see in real data. What's happening here is that the graphics card's memory system is very wide. That's part of the trick that makes a graphics card's memory system so fast. When we're drawing small triangles we're not touching enough neighboring pixels to take full advantage of the width of the memory system and so we lose some efficiency. But the details of shape of the pixel limit depend on your graphics card. In this case, I'm using a <a href=\"http:\/\/www.nvidia.com\/content\/pdf\/data-sheet\/nv-ds-quadro-k600-us.pdf\">nVidia Quadro K600<\/a>.<\/p><pre class=\"codeinput\">opengl <span class=\"string\">info<\/span>\r\n<\/pre><pre class=\"codeoutput\">                          Version: '4.4.0'\r\n                           Vendor: 'NVIDIA Corporation'\r\n                         Renderer: 'Quadro K600\/PCIe\/SSE2'\r\n                   MaxTextureSize: 16384\r\n                           Visual: 'Visual 0x07, (RGBA 32 bits (8 8 8 8), ...'\r\n                         Software: 'false'\r\n        SupportsGraphicsSmoothing: 1\r\n    SupportsDepthPeelTransparency: 1\r\n       SupportsAlignVertexCenters: 1\r\n                       Extensions: {293x1 cell}\r\n               MaxFrameBufferSize: 16384\r\n\r\n<\/pre><p>I've run that code above with a number of different settings and we can use these results to see how those settings affect graphics performance. For example, how does the <a href=\"https:\/\/blogs.mathworks.com\/graphics\/2014\/11\/04\/sortmethod\/\">SortMethod property<\/a> affect performance? The default was childorder because those triangles are all at Z=0. When I switch to<\/p><pre class=\"language-matlab\">set(gca,<span class=\"string\">'SortMethod'<\/span>,<span class=\"string\">'depthsort'<\/span>)\r\n<\/pre><p>I get a different results.<\/p><pre class=\"codeinput\">load <span class=\"string\">r2014b_results<\/span>\r\nload <span class=\"string\">depthsort_results<\/span>\r\ncla\r\nhold <span class=\"string\">on<\/span>\r\nhyperbolicgrid\r\nplot(areas,ntri.\/r2014b_results)\r\nplot(areas,ntri.\/depthsort_results)\r\nxlabel(<span class=\"string\">'Pixels per triangle'<\/span>)\r\nylabel(<span class=\"string\">'Triangles per second'<\/span>)\r\nxlim([0 inf])\r\nylim([0 5e5])\r\nlegend(<span class=\"string\">'childorder'<\/span>,<span class=\"string\">'depthsort'<\/span>)\r\ntitle(<span class=\"string\">'SortMethod'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/areascaling_04.png\" alt=\"\"> <p>You can see that the pixel limit is lower for large triangles, but for small triangles the difference is pretty negligible because of those efficiency issues. You can also see that the depthsort curve is a little unusual because it doesn't \"droop off\" on the left side. This is actually a result of some interesting optimizations that modern graphics cards use to accelerate depthsorting for small triangles.<\/p><p>What about software opengl? How does it's performance compare to the hardware?<\/p><pre class=\"codeinput\">load <span class=\"string\">r2014b_results<\/span>\r\nload <span class=\"string\">sw_results<\/span>\r\ncla\r\nhold <span class=\"string\">on<\/span>\r\nhyperbolicgrid\r\nplot(areas,ntri.\/r2014b_results)\r\nplot(areas,ntri.\/sw_results)\r\nxlabel(<span class=\"string\">'Pixels per triangle'<\/span>)\r\nylabel(<span class=\"string\">'Triangles per second'<\/span>)\r\nxlim([0 inf])\r\nylim([0 5e5])\r\nlegend(<span class=\"string\">'hardware'<\/span>,<span class=\"string\">'software'<\/span>)\r\ntitle(<span class=\"string\">'Hardware vs. Software'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/areascaling_05.png\" alt=\"\"> <p>We can see that using software opengl affects both limits, and quite substantially. The difference between these two curves will, of course, depend on what type of graphics card your system has. But it does highlight the importance of making sure that your graphics card drivers are up to date so that MATLAB can use hardware OpenGL.<\/p><p>And finally, how do different versions of MATLAB compare?<\/p><pre class=\"codeinput\">load <span class=\"string\">r2014b_results<\/span>\r\nload <span class=\"string\">r2014a_results<\/span>\r\ncla\r\nhold <span class=\"string\">on<\/span>\r\nhyperbolicgrid\r\nplot(areas,ntri.\/r2014b_results)\r\nplot(areas,ntri.\/r2014a_results)\r\nxlabel(<span class=\"string\">'Pixels per triangle'<\/span>)\r\nylabel(<span class=\"string\">'Triangles per second'<\/span>)\r\nxlim([0 inf])\r\nylim([0 5e5])\r\nlegend(<span class=\"string\">'R2014b'<\/span>,<span class=\"string\">'R2014a'<\/span>)\r\ntitle(<span class=\"string\">'R2014b vs. R2014a'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/areascaling_06.png\" alt=\"\"> <p>That's interesting, isn't it? It turns out that the old graphics system in R2014a actually had a slightly higher pixel limit than the current version. That's because the new one has added features such as GraphicsSmoothing which incur costs per pixel. But the geometry limit of the old version was only 150,000 triangles per second. That's much, much lower than the geometry limit of the new graphics system. That's because the old graphics system was designed when graphics cards had much lower geometry limits and it had some architectural isses feeding geometry to the card quickly. This bottleneck is one of the things we wanted to make sure we fixed when we were designing a new graphics system for MATLAB.<\/p><p>I should mention here that there are per-pixel costs in initializing the window and in swapping the completed picture onto the screen. This means that to get the most accurate versions of these curves we should really scale the size of the figure window rather than just the size of the triangles we're drawing into the figure window. But doing that made the code a bit more complex, and it really doesn't have a very large effect in this particular case, so I haven't done that here. But you might find that useful if you try to do this sort of area scaling analysis.<\/p><p>As you can see, this view of performance scaling is a powerful one for understanding the bottlenecks in your graphics system. This is often the first technique I try when I'm trying to understand a new graphics performance issue.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_d6d5e81226fe4f64a34e2e0b47b96cc7() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='d6d5e81226fe4f64a34e2e0b47b96cc7 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' d6d5e81226fe4f64a34e2e0b47b96cc7';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2015 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_d6d5e81226fe4f64a34e2e0b47b96cc7()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2014b<br><\/p><\/div><!--\r\nd6d5e81226fe4f64a34e2e0b47b96cc7 ##### SOURCE BEGIN #####\r\n%%\r\n% <https:\/\/blogs.mathworks.com\/graphics\/2015\/01\/20\/performance-scaling\/ Last time> we looked at how the performance of MATLAB's graphics system\r\n% scales with the number of data points. Another interesting lens to look\r\n% at performance scaling with is the way that performance scales with the\r\n% number of pixels. This can actually show us a lot of interesting details\r\n% of the balance of the compute and memory systems of our graphics card.\r\n%\r\n% When we look at performance scaling through this lens, we'll keep coming\r\n% up with charts that look something like this:\r\n%\r\n% <<..\/renderlimit.png>>\r\n%\r\n% In this chart, the X axis is the size of the object we're drawing in\r\n% pixels, and the Y axis is the number of objects we can draw per second.\r\n% As you can see, I've sketched two curves on the chart. The one labeled\r\n% \"Pixel Limit\" is a hyperbola which represents a constant number of pixels\r\n% per second. The other curve is a horizontal line which I've labeled\r\n% \"Geometry Limit\". These are also known as the \"fill rate\" and \"setup\r\n% rate\". To a first order approximation, the \"pixel limit\" is a function of\r\n% the details of the graphics card's memory system, and the \"geometry\r\n% limit\" is a function of the graphics card's GPU. When we measure\r\n% performance, we'll find that we always get numbers that are somewhere in\r\n% the green shaded area. It isn't possible to cross over those two curves.\r\n% In fact, as we'll see, it is usually pretty hard to get results up in\r\n% that corner where the two curves meet. Real, measured data usually rounds\r\n% off the corner between these two curves.\r\n%\r\n% So let's collect some measurements and see how real data compares to this\r\n% sketch. The following chunk of code creates 2,500 triangles and spins\r\n% them around for 150 frames. It spins them using the hgtransform technique\r\n% I described\r\n% <https:\/\/blogs.mathworks.com\/graphics\/2014\/10\/28\/makingthingsmove\/ in this\r\n% post>.\r\n%\r\nntri = 2500;\r\nnframe = 150;\r\nradii = linspace(0,1,75);\r\nareas = (171.5*radii).^2 * 3 * sqrt(3) \/ 4;\r\nseconds = zeros(1,length(radii));\r\nfor j=1:length(radii)\r\n    rad = radii(j);\r\n    cla\r\n    axis square\r\n    axis off\r\n    xlim([-1 1])\r\n    ylim([-1 1])\r\n    g = hgtransform;\r\n    theta = linspace(0,2*pi,ntri);\r\n    v = [rad*cos(theta)', rad*sin(theta)'];\r\n    x = 1:ntri;\r\n    o1 = floor(ntri\/3);\r\n    o2 = floor(2*ntri\/3);\r\n    f = [x', 1+mod(x+o1,ntri)', 1+mod(x+o2,ntri)'];\r\n    h = patch('Faces',f,'Vertices',v,'FaceVertexCData',x', ...\r\n              'FaceColor','flat','EdgeColor','none', ...\r\n              'Parent',g);\r\n    drawnow\r\n    t = nan(1,nframe);\r\n    rotmat = makehgtform('zrotate',pi\/20);\r\n    for k=1:nframe\r\n        tic\r\n        set(g,'Matrix',get(g,'Matrix') * rotmat);\r\n        drawnow\r\n        t(k) = toc;\r\n        if sum(t(1:k)) > 1.5\r\n            break\r\n        end\r\n    end\r\n    seconds(j) = median(t(isfinite(t)));\r\nend\r\n\r\n%%\r\n% Now we can plot these results like so:\r\nplot(areas,ntri.\/seconds)\r\nxlabel('Pixels per triangle')\r\nylabel('Triangles per second')\r\n\r\n%%\r\n% That looks kind of like the curve I sketched, but with a lot of noise for\r\n% the small triangles. To make things clearer, lets add a \"hyperbolic\r\n% grid\" with the following function:\r\n%\r\n%   function hyperbolicgrid\r\n%     radii = linspace(0,1,75);\r\n%     areas = (171.5*radii).^2 * 3 * sqrt(3) \/ 4;\r\n%     for j=1:8\r\n%       line(areas,j*1e9.\/areas,'Color',[.875 .875 .875], ...\r\n%            'HandleVisibility','off')\r\n%     end\r\ncla\r\nhold on\r\nhyperbolicgrid\r\nplot(areas,ntri.\/seconds)\r\nxlabel('Pixels per triangle')\r\nylabel('Triangles per second')\r\nxlim([0 inf])\r\nylim([0 5e5])\r\ntitle('Performance Scaling')\r\n\r\n%%\r\n% Now we can see that the curve doesn't actually follow one of the\r\n% hyperbolas. The fill rate for small triangles is actually quite a bit\r\n% lower than the fill rate for large triangles. This is something that\r\n% you'll often see in real data. What's happening here is that the graphics\r\n% card's memory system is very wide. That's part of the trick that makes a \r\n% graphics card's memory system so fast. When we're drawing small triangles\r\n% we're not touching enough neighboring pixels to take full advantage of\r\n% the width of the memory system and so we lose some efficiency. But the\r\n% details of shape of the pixel limit depend on your graphics card. In this\r\n% case, I'm using a <http:\/\/www.nvidia.com\/content\/pdf\/data-sheet\/nv-ds-quadro-k600-us.pdf nVidia Quadro K600>.\r\nopengl info\r\n\r\n%%\r\n% I've run that code above with a number of different settings and we can\r\n% use these results to see how those settings affect graphics performance.\r\n% For example, how does the\r\n% <https:\/\/blogs.mathworks.com\/graphics\/2014\/11\/04\/sortmethod\/ SortMethod\r\n% property> affect performance? The default was childorder because those\r\n% triangles are all at Z=0. When I switch to \r\n%\r\n%   set(gca,'SortMethod','depthsort')\r\n%\r\n% I get a different results.\r\nload r2014b_results\r\nload depthsort_results\r\ncla\r\nhold on\r\nhyperbolicgrid\r\nplot(areas,ntri.\/r2014b_results)\r\nplot(areas,ntri.\/depthsort_results)\r\nxlabel('Pixels per triangle')\r\nylabel('Triangles per second')\r\nxlim([0 inf])\r\nylim([0 5e5])\r\nlegend('childorder','depthsort')\r\ntitle('SortMethod')\r\n\r\n%%\r\n% You can see that the pixel limit is lower for large triangles, but for\r\n% small triangles the difference is pretty negligible because of those\r\n% efficiency issues. You can also see that the depthsort curve is a little\r\n% unusual because it doesn't \"droop off\" on the left side. This is actually\r\n% a result of some interesting optimizations that modern graphics cards use\r\n% to accelerate depthsorting for small triangles.\r\n%\r\n% What about software opengl? How does it's performance compare to the\r\n% hardware?\r\nload r2014b_results\r\nload sw_results\r\ncla\r\nhold on\r\nhyperbolicgrid\r\nplot(areas,ntri.\/r2014b_results)\r\nplot(areas,ntri.\/sw_results)\r\nxlabel('Pixels per triangle')\r\nylabel('Triangles per second')\r\nxlim([0 inf])\r\nylim([0 5e5])\r\nlegend('hardware','software')\r\ntitle('Hardware vs. Software')\r\n\r\n%%\r\n% We can see that using software opengl affects both limits, and quite\r\n% substantially. The difference between these two curves will, of course,\r\n% depend on what type of graphics card your system has. But it does\r\n% highlight the importance of making sure that your graphics card drivers\r\n% are up to date so that MATLAB can use hardware OpenGL.\r\n%\r\n% And finally, how do different versions of MATLAB compare?\r\nload r2014b_results\r\nload r2014a_results\r\ncla\r\nhold on\r\nhyperbolicgrid\r\nplot(areas,ntri.\/r2014b_results)\r\nplot(areas,ntri.\/r2014a_results)\r\nxlabel('Pixels per triangle')\r\nylabel('Triangles per second')\r\nxlim([0 inf])\r\nylim([0 5e5])\r\nlegend('R2014b','R2014a')\r\ntitle('R2014b vs. R2014a')\r\n\r\n%%\r\n% That's interesting, isn't it? It turns out that the old graphics\r\n% system in R2014a actually had a slightly higher pixel limit than the current\r\n% version. That's because the new one has added features such as\r\n% GraphicsSmoothing which incur costs per pixel. But the geometry limit of \r\n% the old version was only 150,000 triangles per second. That's much, much \r\n% lower than the geometry limit of the new graphics system. That's because \r\n% the old graphics system was designed when graphics cards had much lower \r\n% geometry limits and it had some architectural isses feeding geometry to \r\n% the card quickly. This bottleneck is one of the things we wanted to make sure we \r\n% fixed when we were designing a new graphics system for MATLAB.\r\n%\r\n\r\n%%\r\n% I should mention here that there are per-pixel costs in initializing the\r\n% window and in swapping the completed picture onto the screen. This means\r\n% that to get the most accurate versions of these curves we should really\r\n% scale the size of the figure window rather than just the size of the\r\n% triangles we're drawing into the figure window. But doing that made the\r\n% code a bit more complex, and it really doesn't have a very large effect\r\n% in this particular case, so I haven't done that here. But you might find\r\n% that useful if you try to do this sort of area scaling analysis.\r\n%\r\n% As you can see, this view of performance scaling is a powerful one for\r\n% understanding the bottlenecks in your graphics system. This is often the\r\n% first technique I try when I'm trying to understand a new graphics\r\n% performance issue.\r\n\r\n##### SOURCE END ##### d6d5e81226fe4f64a34e2e0b47b96cc7\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/graphics\/files\/feature_image\/thumbnail.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>Last time we looked at how the performance of MATLAB's graphics system scales with the number of data points. Another interesting lens to look at performance scaling with is the way that performance... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/graphics\/2015\/02\/10\/area-scaling\/\">read more >><\/a><\/p>","protected":false},"author":89,"featured_media":196,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[8],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/190"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/users\/89"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/comments?post=190"}],"version-history":[{"count":5,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/190\/revisions"}],"predecessor-version":[{"id":195,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/190\/revisions\/195"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media\/196"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media?parent=190"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/categories?post=190"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/tags?post=190"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}