MATLAB Answers

Dhanya
8

Increase the plotting performance in the MATLAB level (drawmode/ optimizing rendering/ down sampling etc)

Asked by Dhanya
on 5 Nov 2015
Latest activity Commented on by Walter Roberson
on 4 Jan 2018
Problem statement: Increase the plotting performance in the MATLAB level (drawmode/ optimizing rendering/ down sampling etc)
Background: We are working on a MATLAB based framework for analysis and visualization of data. The information that we use for plotting is very huge. The number of data points are in the range of ~10E7 or more and we are facing MATLAB performance issues when we zoom/pan/maximize/minimize. We urgently need to improve the performance. The requirement is to have the complete information in the plot but the end user chooses to enable or disable particular lines based on the need. As a framework owner we do not have any control on the number of data points that are used for the plot or remove the overlapping points.
Bottom line is we cannot modify the data to be plotted so we will continue to have huge number of points. We can only try from the MATLAB layer to increase the performance as requested above.
Please help us to improve the performance with your experience. Looking forward for your answers.
Thanks, Dhanya

  1 Comment

Thanks for this interesting question. It started an important discussion, therefore I've voted for it.

Sign in to comment.

10 Answers

Answer by Yair Altman on 6 Nov 2015
Edited by Yair Altman on 6 Nov 2015

Matlab's new graphics engine ("HG2", introduced in R2014b) indeed degraded the performance for plotting numerous data points, compared to the earlier HG1 (R2014a and earlier). Still, this does not mean that you must give up on HG2's better visualization. There are multiple things that you can do to improve the performance and reactivity of your graphics, to the point where performance is no longer a limiting factor and you just keep HG2's better visualization.
In addition to the pointers by Walter and Mike, here are some additional resources that you may find useful (apologies for the plugs, but this is one of my main topics of ongoing research...):
The last article in particular details several techniques that I usedin a situation very similar to yours. In addition to those techniques, some additional techniques for speeding up graphic objects creation that I’ve found useful over the years include:
  • Avoid plotting non-visible elements, including elements that are outside the current axes limits, or have their Visible property set to ‘off’ or have a color that is the same as the axes background color.
  • Avoid plotting overlapped elements, esp. those that are occluded by non-transparent patches, or lines having the same coordinates.
  • Reduce the number of plotted objects by combining lines, patches etc. into a single object using data concatenation, with NaN values as separators.
  • Avoid using the scatter function with fewer than 100 data points – instead, duplicate these points so that scatter will work with more than 100 points, where vectorization kicks in ( details ), or even better: use line rather than scatter.
  • Use low-level rather than high-level plotting functions – i.e., line instead of scatter/plot/plot3; surface instead of surf.
  • Avoid creating straight line with multiple data points – instead, only keep the end-points for plotting such lines. I find that this is a very common use-case, which is often overlooked and could have a significant performance impact.
  • Avoid using plot markers if possible, and use simple markers if this cannot be avoided. Various markers have different performance impacts in various situations, but ‘.’ and ‘o’ are typically faster than others.
  • Use the plot function’s input triplets format, rather than multiple calls to plot. For example:
plot(data1x,data1y,'r', data2x,data2y,'g', data3x,data3y,'b', ...);
  • Set the axes properties to static values before plotting, in order to avoid run-time dynamic computation and update of things like the limits, tick-marks etc.
  • Avoid creating legends or colorbars initially – let the user create them by clicking the corresponding toolbar icon if needed. Legends and colorbars take a second or more to create and can often be avoided in the initial display. If this cannot be avoided, then at least create static legends /colorbars.
  • Only call drawnow once you’ve finished plotting. I’ve seen numerous cases where users call drawnow within the plotting loop and this has a horrendous performance impact. However, note that in some cases drawnow is very important ( example1, example2 ).
  • Generate the plot while the figure is hidden.
  • Data-reduce the plotted data. We can program this ourselves, or use former MathWorker Tucker McClure’s reduce_plot utility (a POTW selection) to do it for us. Data reduction is especially important when displaying images that do not need to be zoomed-in, but also significantly improves zooming and panning speed.
  • Cast image data to uint8 before using image or imagesc to display the image.
  • Avoid clearing/deleting and then recreating the axes when we need to replot – instead, just delete the relevant axes children objects and replot in the existing axes.
  • Avoid using the axes function to set the focus on a specific axes – instead, set the figure’s CurrentAxes property, or pass the axes handle directly to the plotting function.

  5 Comments

HG2 has much more capabilities than HG1. Then before comparing the performance, you have to define at first, what performance exactly means. Is it the time required to draw one line in an existing axes object, the time until the figure appears completely on the screen, or is it the time until the user got the plot exactly as he needs it including the programming time and usage of external tools?
If I need a diagram with line-smoothing and the x- and y-axis through the center, HG2 is so many times more efficient, that a comparison of the speed becomes meaningless. And when I draw 5000 simple lines and it does not matter that the pixel-appearence looks like a 8-bit computer game from the eightys, HG1 is much faster. This might matter e.g. for psychological examinations, when the reaction time of a person is determined and the frequency of the monitor is the limitng factor.
Even if we consider HG1 only, the performance is substantially influenced by the used render: While OpenGL handles large data more efficiently than Painters, it reduces the resolution to single precision and if e.g. the data contain datenum values with a resolution of seconds the display is not usable.
I'm convinced, that the purpose of HG2 was to improve the quality of graphics. This requires more computations and it would be magic, if this does not reduce the processing speed. And according to my own experiences and what I've read in Matlab forums, HG2 takes more time to create equivalent diagrams as HG1, but with HG1 it was nearly impossible without smart external tools to create diagrams, which are equivalent to HG2.
I'm using a tool in the daily routine, which reads friles from the disk, processes the data in about 200'000 lines of code and creates 4 figures with 16 axes on each page, 6 line/patch objects per axes and some text. Matlab 5.3 (before Java) took more time for the file import than for the graphics, but it was impossible to draw transparent patch objects, such that it was impossible to draw standard deviations around two lines simultaneously. In Matlab 6.5 the OpenGL renderer allows to draw with the alpha blending and the time for the graphics exceeded the time for reading the files. The total processing speed degraded from 5.3 to 6.5 and this trend went on to R2009b and R2011b. But the debugger became much more powerful and e.g. M-Lint solved a lot of problems extremely efficiently. So if I define performance as the time from starting the programming until I have the results of the measurement, modern Matlab versions are much better, also the pure runtime is worse.
While the graphics have not been the bottleneck in 5.3, I did not optimize this e.g. considering the excellent tips in http://undocumentedmatlab.com/blog/plot-performance. But for R2009b these tips bacame useful and reduced the runtime remarkably. After a the redesign of the graphics part the code was not compatible to 5.3 anymore and a comparison of the speed was meaningless.
My personal opinion: HG2 is better then HG1. Some details might be faster in HG2, when the programmers spent time for optimizing the code. But the increased power is expected to require more resources, such that buying a faster computer is an efficient solution, when the runtime matters.
@Yair: Thank you very much for your exhaustive tips for improving the plot performance. You must have spent many hours in experimenting with Matlab and published the found results. This helped me a lot to reduce the runtime of a program I've written for clinical decision making in the daily routine. Now it needs less than 5 seconds, such that neither the patients nor the staff gets nervous waiting for the results.
Matlab's own bench command shows this degradation, after you
modify bench.m to enable a comparison with HG1 [R2014a].
Just to be clear, the reason we changed the 2D bench function in 14b was because the old version wasn't actually large enough to measure anything graphics related. Since the purpose of the bench function is to tell you how good "your machine" is for running MATLAB, it is important that the graphics portion pushes enough data through the rendering pipeline to exercise the graphics card.
Just a slight side note related to this discussion... in my experience, HG2 is significantly slower than HG1 when the user is plotting more data than he or she "should." And while I fully understand that the Mathworks isn't, and maybe shouldn't be, trying optimize its graphics for workflows like this, I suspect that a large number of users plot more data than they should on a regular basis.
For distribution-level software that's going to be used repetitively (such as the type detailed in the original question), the techniques Yair listed can be used to overcome most of the slowness.
However, there are many times when the effort required to parse the data to be plotted down to its most efficient form is more time-consuming than just waiting for the slow graphics. For example, yesterday, I was doing some analysis of a parameter sensitivity study, where I systematically varied a few hundred parameters within a model. My analysis plot consisted of a figure with 77 axes, each containing stacked bar plots. I often squish an absurd number of axes onto a figure like this, and then explore via expandAxes.m. And HG2 is much slower than HG1 here (bar plots are particularly problematic...). Is this user error? Maybe. I certainly would never try to give software with this sort of plotting routine to anyone else (could create the same stacked-histogram type of plot using low-level patches, probably). But it is a little aggravating that Matlab graphics suffer during the sort of prototyping, throw-everything-at-the-wall-and-see-what-sticks sort of workflow that the rest of Matlab excels so well at.
HG2 is also a bit less forgiving of plotting way, way more than you should. HG1 could be crashed mid-render, via a control-C escape. In my experience, HG2 seems determined to complete the task it if kills it (and kill it it does... I've accidentally frozen Matlab a couple times by accidentally telling it to plot the entirety of 9000x9000-pixel DEM images rather than my little area of interest).
Overall, I like HG2 graphics better than HG1. But from my point of view, it's slower, regardless of the hard work and optimization that has gone into the large-data side of its development.

Sign in to comment.


Answer by Walter Roberson
on 5 Nov 2015

A lot depends upon the release you are using, and the operating system, and the graphics cards, and some of the fine details of the plot commands used. You have not given information on any of those.
However, the way you are describing your situation, it appears that at most you have control over the minimum MATLAB software release used, and that you have no control over anything else, especially not what plot commands are actually used. Under those circumstances, your requirements are not feasible.
If, on the other hand, the user-supplied data is passed to your routines and you have control over exactly how it is displayed, then you do have control over the number of data points plotted, which makes a big big difference in the feasibility.
A key trick here is that Zoom and Pan both have a Pre-Action Callback (and a Post-Action Callback too.) This allows you to filter the data to be plotted to only submit to the graphics system the data points that would be visible and of meaningful contribution with the current view and display resolution: when you get the zoom or pan request, you compute what would be in the new view and you submit that to the graphic system.

  0 Comments

Sign in to comment.


Answer by Mike Garrity
on 5 Nov 2015

There isn't a "one size fits all" answer for this. We'd need to know more about what you're doing.
The first step is to use the profiler and see what it tells you. Another step would be to read some of things I've posted on the subject on the MATLAB Graphics blog. In particular, there were a number of good suggestions in the comments thread for this post. And of course, creating a simplified version of your case and posting it here would give people something concrete to comment on.

  0 Comments

Sign in to comment.


Answer by Jan
on 8 Nov 2015
Edited by Jan
on 8 Nov 2015

You wrote:
As a framework owner we do not have any control on the number of
data points that are used for the plot or remove the overlapping points.
I think, this is the core problem, and not Matlab's performance.
You cannot display 1e8 points on a LCD screen, because this exhausts the number of available pixels. Trying to squeeze subpixel information in a plot is a waste of time.
Human cannot perceive such an information density also. Beside the technical and psychological limitations, the performance might be a secondary problem only.
The Douglas-Peucker method allows to reduce the information without loosing important details depending on the resolution of the display and the receiving human. See also: FEX: Plot (Big) (suggested by Yair already as "reduce_plot").

  1 Comment

MATLAB's line object actually does reduce the number of points before sending them to the graphics card. It's not Douglas-Peucker. It's a very old bit of MATLAB code which is designed to be particularly good at the most common MATLAB plots. In particular, it's really careful about not losing the details of narrow peaks. Also, it's a sweep method rather than a recursive subdivision method because that often works better with MATLAB's memory management. You're right that there are cases where something like Douglas-Peucker is a more appropriate choice, but in many cases I think that you'll find that the default curve thinning is actually the right choice.
If you look at the graphs at the end of this post on the MATLAB Graphics blog, you can see how the different chart types scale with the number of datapoints. As you can see, in R2014b that became quite a bit better for most of the charts. In particular, look at area and scatter. They had terrible scaling characteristics in earlier releases.
We focused pretty closely on getting the slope of those curves down on the right side of that chart. But as you can see, on the left hand side things aren't as good. That's the case that Yair's talking about above. There's a constant cost for things like object creation. For a large amount of data, that gets amortized, but when the amount of data is small, you can clearly see that cost. We're continuing to work on improving that part. A lot of it is just that the old object creation code had gotten lots of tiny performance tweaks for more than 20 years, and it's going to take some time to catch up with it.
One really interesting thing on those two charts is that the curve for plot doesn't really look very different. There's that constant offset again, but the slopes of the right hand sides are nearly identical. That's because a lot of the large data optimizations like the curve thinning that I described earlier were already part of plot's line object in earlier releases. We've basically been focused on getting all of the other objects caught up to that one on performance scaling.
I do have another post about performance coming to the MATLAB Graphics blog soon. This one's going to focus on memory consumption, which is another important factor to consider here. Way back when I used to design graphics hardware, I used to say that it was really just advanced memory system design. Getting enough compute was usually the easiest part of designing a balanced pipeline.

Sign in to comment.


Answer by Dhanya
on 9 Nov 2015

Thanks to all for the overwhelming answers for this post. I'll get back to you with more specific details of our problem.

  0 Comments

Sign in to comment.


Answer by Bruno Luong
on 9 Nov 2015
Edited by Bruno Luong
on 9 Nov 2015

I would like to submit another issue with HG2 performance that is blocking in my case.
Context: I have a high speed camera that acquires some kind of gray images with a speed of about 100 FPS.
Goal: I want to plot an image as fast as I can with some other basic information overlaying on the image.
The plot is carried out by a function "Update_Plot" called in a continuous loop.
Essentially this function does nothing but a bunch of SET commands on an existing objects, and terminates with a drawnow(). To fix an idea, the objects consist of 1 image of about 500 x 200 in resolution, 15 texts, and 25 lines. It does not use any factory smoothing capability. There is no graphical object creation in the function.
If an camera images is received during this function is invoked it will be throw away. So the display speed depends only on the capability of MATLAB of updating as fast as it can of the graph.
Here is the results, carefully measured:
  • R2014A (HG1) 27 FPS, smooth display
  • R2015B (HG2) 11 FPS, important jitter in the display
They are performed on the same computer: Win64, Windows 10 OS, i7 4500 dual core laptop, latest Nvidia driver.
Here is a test on another computer with: Win64, Windows 7 OS, i7 3960 desktop, Nvidia graphic card and driver.
  • R2012A (HG1) 54 FPS, smooth display
As you can see, performance on HG2 is quite low and the jitter creates uncomfortable visual effects for users. This issue is very problematic on our SW development roadmap, we can no longer ensure our soft work reliable on latest HW and SW.
I'm not sure what I could do to get the performance back.
For now we are stuck with an old MATLAB versions, but trend of using Windows 10 and new HW by our clients tells me that this solution can be used for a short time (1-2 year). So this cause me a big concern about the future.

  9 Comments

Ah, that makes sense. It'd be really interesting to know what events were causing the most trouble, but that information is surprisingly difficult to get.
You will need to let some callbacks through occasionally or you're going to have things like window resize information piling up waiting to get through.
So I assume that's just addressed the frames which were a lot slower than the others. I'd still be interested in knowing enough details to know what the bottleneck is for your median frames. We're looking to improve our profiling tools in this area, and understanding more about the experiences of users who are struggling with these types of problems would be very helpful.
Mike,
1. is there anyway to get some profiling details of a DRAWNOW command? 2. What is the recommendation of when using DRAWNOW, when using REFRESHDATA?
> 1. is there anyway to get some profiling details of a DRAWNOW command?
Currently no. Our support team has some profiling tools, but they're definitely not ready for prime time. But sending them repro steps for some interesting cases should help us figure out what we need to do to get them ready for prime time. So I would encourage you to do that.
> 2. What is the recommendation of when using DRAWNOW, when using REFRESHDATA?
The refreshdata function is a fairly specialized beast. Really its only job is for the case where you've got a plot that you created with something like the plot browser, so that it has a reference to the variables you created from, and the values of those variables changed. In this case, the plot doesn't know because of MATLAB's copy-on-write memory management. So the refreshdata function tells them to check for updates.
The drawnow function is much more general purpose. In fact, as you saw here, it's probably trying to do too many jobs. The description on the doc page is about the best we have. Basically drawnow is the gatekeeper for the connection between MATLAB's compute thread(s) and its rendering thread(s). So its controlling any communication that has to cross between them. That includes updates to objects being drawn, mouse events, window resizes, and various notifications from the operating system.

Sign in to comment.


Answer by Bruno Luong
on 9 Nov 2015

Sorry for cross posting, but we somehow pinpoint to the fact that MATLAB handle poorly some latest/advanced drivers
To Mike: I will try to make a minimal example, but as you have seen, the issue is also somewhat related to HW and drivers, so you might see something difference than with my setup.

  5 Comments

So we need nVidia to confirm this, but it looks like they're not supporting the GTX 560 Ti on the ODE drivers. Those are the ones whose version starts with '10.'. You can find the list of supported GPUs in the release notes.
It looks like they want you to use the drivers on the '9.' line. They just dropped a new WHQL version on that line yesterday (358.91):
It still lists the 560 in the release notes, but we haven't had a chance to try it yet.
Hopefully we'll get some more details from nVidia on this, but I expect that you're seeing some sort of software emulation of some new feature the ODE drivers are expecting that's not available on the 560 GPU.
Here is Mathworks answer. Basically they say , downgrade the driver or live with it ! WTF
Technical Support Case #01600806
"I believe you were aware of the graphics driver issue. One possible solution would be reverting to an older version of the driver that should work correctly. Drivers with version 344 and above have performance issues while drivers with versions 341 and below do not. We suspect that there has been some major change made by NVIDIA for version 344 since they still keep version 341 and release security fixes for it. If you couldn't downgrade the driver, we couldn't do too much in this case. I'm afraid you would need to run this on another computer. I'm sorry about that."
Ps: My parallel toolbox CUDA doesnt work with that old driver , so for me 2 toolboxes are becoming useless -parallel toolbox and -simulink 3d animation (try vrmemb demo and see it locks the PC)
My GPU is fully supported by the NVIDIA driver
Vendor: 'NVIDIA Corporation'
Renderer: 'GeForce GTX 770M/PCIe/SSE2'
RendererDriverVersion: '10.18.13.5891'
RendererDriverReleaseDate: '05-Nov-2015'
MaxTextureSize: 16384
Visual: 'Visual 0x07, (RGBA 32 bits (8 8 8 8), Z depth 16 bits, Hardware acceleration, Double buffer, Antialias 8 samples)'
Software: 'false'
HardwareSupportLevel: 'full'
SupportsGraphicsSmoothing: 1
SupportsDepthPeelTransparency: 1
SupportsAlignVertexCenters: 1
Extensions: {322x1 cell}
MaxFrameBufferSize: 16384

Sign in to comment.


Answer by Bruno Luong
on 11 Nov 2015

There is a hope that TMW might able to fix it, since HG1 can handle well new driver.

  2 Comments

Bruno, did you delete the comment I was responding to in my last comment above? That's really not a good practice.
And no, the fact that HG1 worked on a card with an unsupported driver doesn't tell you much. When nVidia's drivers find an unsupported card, they pass through the calls which that card supports and emulate the others using a software implementation. It's quite likely that HG1 didn't use any features which were outside the subset that it could pass through, while HG2 is using some feature that is emulated. We can't know that we should not use this feature in this case because the driver tells us it is a supported feature.
No, I did not delete anything, at least not intentionally. It might be possible that I make a mistake. I'm still not very familiar with ANSWER interface.
Sorry if I did.
Edit: I'm sure I did not since I can only see [Delete] over my own posts

Sign in to comment.


Answer by Bruno Luong
on 11 Nov 2015

On my LAPTOP with Nvidia GF 730M I can't get the FPS above 12, regardless the driver (up to 385.91 where I install about a week).
Things is we never have to care about that kind of "details" with HG1. It's kind of scary now that we have to look at HW and driver, and I can hardly enforce my clients to follow such restrictive PC requirement. And even if we select the best HW and drivers there are still some significant drop up of graphical rendering between HG1 and HG2, at least for my application.

  1 Comment

Again, it would really be helpful if you could pass along some details of your application. I'd love to see what the bottleneck is. It would also help us in developing tools to make this sort of analysis easier for users to do themselves.
And yes, we are aware of the tradeoffs in taking advantage of new graphics features. We feel quite a bit of angst every time we add something which isn't available on all cards. But we also have to pay attention to the fact that some users have bought powerful cards with a lot of capabilities that they would like to take advantage of from within MATLAB.

Sign in to comment.


Answer by Xiangrui Li on 4 Jan 2018
Edited by Xiangrui Li on 4 Jan 2018

I found this thread while looking for solutions to speed up patch update. My figure has four patches, each with ~32k vertices. Even after I avoid patch overlays by combining into one patch at each axis, the figure update still takes ~600 ms while my computation takes only ~20 ms. This is measured as following after updating data:
set(hPatch, 'FaceVertexData', updatedData);
tic; drawnow; toc
I tried various ways recommended by Matlab and above tips, including changing axis mode to manual, doubleBuffer off for figure, flat faces instead of interp faces, and uint8 rather than single FaceVertexData. None of these gives significant speedup in my case.
The only effective way I found so far is to change VertexNormalsMode from default 'auto' to 'manual'. This reduces ~600 ms to ~200 ms. This is against the documentation, since I create patch by setting Faces and Vertices only, so rely on 'auto' VertexNormals. It will fail normally, but my trick is to 'drawnow' once after setting Faces and Vertices, then change VertexNormalsMode to 'manual'. 200 ms is still sluggish visually, but it is the best I have for now.
Note that this behavior is consistent among Windows/Linux/OSX and multiple Matlab versions I have tested.

  1 Comment

tic; drawnow; toc measures the time it takes to submit the graphics commands to the multithreaded graphics back-end; that back-end will then proceed asynchronously to update the screen as it computes what should be displayed.

Sign in to comment.