eclipse / swtchart

Eclipse Public License 2.0
47 stars 41 forks source link

Performance Improvement using ImageData #175

Open ifsarbaby opened 4 years ago

ifsarbaby commented 4 years ago

Hi SWTChart team,

First, I want to say thank you for making such a great charting library. I'm a long time SWT developer and I'm glad to see that cool tools such as this are still being developed.

In my current application I am plotting large amounts of data (30,000 points) as line charts or scatter plots. I would like to refresh the plots quickly. I noticed that the performance of scatter plots was very slow. Specifically it would take 2.5s to render 30000 points (without compression). Looking at how LineSeries data was plotted and doing profiling of the source code, the GC drawing methods are very expensive to draw a symbol and and accounted for the vast majority of the render time. (There are some other potential savings that I see in the code, but nothing close to the time spent calling the GC methods)

To solve this, I modified the LineSeries code and cloned the functionality to draw directly on an imagedata object by setting the pixels required. I made a second version of many of the LineSeries functions (like drawLineAndArea) that use an ImageData directly instead of GC. After rendering to the ImageData, A single GC.drawImage is required to draw the points over the background chart.

The resulting performance is ~2ms to plot the same points. This is a 1000x increase and allows me to plot the data as it arrives in the system in a "real-time" display. Out of the 2ms, most of the time (80%) is the gc.drawImage. For multiple line series on the same chart, I can resuse the ImageData making the incremental rendering of layers 5000x faster than before.

Similarly, I can improve the line rendering slightly (by a factor of 3-4x only) by drawing lines directly on the ImageData using a Bresenham line algorithm. (the GC.drawline method is reasonably efficient vs self created one, with only a 3-4x performance difference)

I would very much like to see a Performance increase of this powerful SWT library. I offer up the code that I modified, if it is useful to this team. It is not production ready, but could be completed and integrated with someone who has higher knowledge of the library than myself. I myself, do not have much time that I can offer to support this tool development.

Please let me know if it is of use, and I can package it up.

Thanks,

eselmeister commented 4 years ago

@ifsarbaby Yep, we are working steadily to improve the plotting performance. An optimization has been recently added to speed up the selection process by creating an image of the chart and setting it in the background as long as the selection process lasts:

https://github.com/eclipse/swtchart/issues/85

We would be highly interested in your solution. Due to compatibility reasons, code needs to be tested and validated on several OS. We often see, that minor problems occur on macOS and GTK3.

It would be great if you could share your code with some explanations. We could then inspect it and probably merge it into the SWTChart code base.

ifsarbaby commented 4 years ago

Hi, Sorry for the delay in this, I had other items I needed to address. I wanted to clean up the code and do some more testing before I pass this on. I also improved the algorithm further, and included clipping (i.e. never render a pixel outside of the visible area) to furthur improve performance. The solution that I came up with is really quite fast, and I am happy that we can plot data in real-time. I am refreshing data in multiple plots at 30Hz (50,000 points) and it is buttery smooth.

Please find attached the following, with some explanation of what I did:

The FastLineDrawingSWT methods can be extended to work directly on a bitmap, and could integrate nicely with what you mentioned. I actually turn compression off, on my datasource, as it is faster that with it. The LineSeries.drawLine() method checks if the X and Y already maps to the same pixel coordinate as the previous and therefore will skip it. So it's more of an "on the fly" compression that compressing the data first.

Let me know if I can be of any further help.

SWTChart_Performance.zip

cheers,

eselmeister commented 4 years ago

Hi ifsarbaby,

thanks for feedback. I had a look at the code. It could be an improvement for SWTChart and hopefully helps to plot huge data sets in a performant way. IMHO, it's a good demo. Before the code will be merged for testing purposes, some additional steps are required:

The official way to contribute code to SWTChart is to create a Pull Request (PR). Before a PR will be created, I would recommend to address the following issues:

As an example, have a look at the "buffered selection" option. Improvements and testing could be then implemented stepwise to avoid breaking existing code and functionalities.

Best, Philip

[1] https://www.eclipse.org/legal/ECA.php

Am 20.08.20 um 00:53 schrieb ifsarbaby:

Hi, Sorry for the delay in this, I had other items I needed to address. I wanted to clean up the code and do some more testing before I pass this on. I also improved the algorithm further, and included clipping (i.e. never render a pixel outside of the visible area) to furthur improve performance. The solution that I came up with is really quite fast, and I am happy that we can plot data in real-time. I am refreshing data in multiple plots at 30Hz (50,000 points) and it is buttery smooth.

Please find attached the following, with some explanation of what I did:

  • PlotArea.java - modified to use the new methods added to LineSeries
  • LineSeries.java - added new methods to paint using ImageData (instead of GC). I preserved the original methods, and only added new methods
  • ChartLayout.java - I modifed Chartlayout to include an option (setAdjustForMostLeftRightTickLabel()) that disables calling adjustForMostLeftRightTickLabel(). When this is enabled, the location of the plot area can change based on the axis labels, and that creates a sometimes jittery graph if you are doing real-time plotting.
  • FastLineDrawingSWT - A custom line drawing algorithm that uses ImageData. Currently supports lines and symbols, however it has some limitations: No line styles (just width and color is supported), and only square symbols. However this could be added on at some point.

The FastLineDrawingSWT methods can be extended to work directly on a bitmap, and could integrate nicely with what you mentioned. I actually turn compression off, on my datasource, as it is faster that with it. The LineSeries.drawLine() method checks if the X and Y already maps to the same pixel coordinate as the previous and therefore will skip it. So it's more of an "on the fly" compression that compressing the data first.

Let me know if I can be of any further help.

SWTChart_Performance.zip https://github.com/eclipse/swtchart/files/5099689/SWTChart_Performance.zip

cheers,

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/eclipse/swtchart/issues/175#issuecomment-676791682, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFHUTZU6VAGYNYZRMUH5ADSBRJWLANCNFSM4NYRXGUA.

--

OpenChrom - the open source alternative for chromatography / mass spectrometry
Dr. Philip Wenig » Founder » philip.wenig@openchrom.net » http://www.openchrom.net
ifsarbaby commented 4 years ago

Gruesse Eselmeister

Regarding your questions:

I have completed the eclipse contributors agreement as provided. However, I don't have time to contribute anything more than what I provided at this time -- I am only passing on the solution in hopes that someone else can take it further that understands the mechanics of this library.

I do agree with the approach of having the user select the plotting method. That would be logical, and allow for the new algorithm to be used, even with limited features. I'll take a look at the buffered section.

Cheers,

eselmeister commented 4 years ago

Hi,

ok, great that you have completed the Eclipse Contributors Agreement. It's a pre-requisite that additional code is merged via a Pull Request. Hence, I would recommend to proceed as follows:

A) FastLineDrawingSWT -> Rename to FastGC (probably it will be used for more than just line drawing in the future) B) Place FastGC in the package "org.eclipse.swtchart.internal" C) The package declaration needs to be adjusted to "package org.eclipse.swtchart.internal;" D) Add the copyright header [1] (TODO) E) Create a PR so that I can review the code and merge it if all checks have been passed successfully

The class FastGC is the most important piece here, as I assume. Just placing it in the internal package doesn't change or modify existing code. After a successful merge, I will inspect your modifications on "ChartLayout", "PlotArea" and "LineSeries". If possible, I can try to add an option to enable the FastGC option separately for a distinct line chart. If that works fine, we can try to optimize the code stepwise.

Best, Philip

[1] /   Copyright (c) 2020 SWTChart project.     This program and the accompanying materials are made   available under the terms of the Eclipse Public License 2.0   which is available at https://www.eclipse.org/legal/epl-2.0/     SPDX-License-Identifier: EPL-2.0     Contributors:   TODO: YOUR NAME OR NICKNAME - initial API and implementation  /

Am 20.08.20 um 21:29 schrieb ifsarbaby:

Gruesse Eselmeister

Regarding your questions:

  • The code for FastLineDrawingSWT is my own code.
  • I have not tested this on mac or linux, however I would anticipate no problems. The algorithm uses java methods and not any SWT system OS calls that are known to cause problems.

I have completed the eclipse contributors agreement as provided. However, I don't have time to contribute anything more than what I provided at this time -- I am only passing on the solution in hopes that someone else can take it further that understands the mechanics of this library.

I do agree with the approach of having the user select the plotting method. That would be logical, and allow for the new algorithm to be used, even with limited features. I'll take a look at the buffered section.

Cheers,

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/eclipse/swtchart/issues/175#issuecomment-677856900, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFHUT2Z3YJI7EGNYMQWDHTSBV2RXANCNFSM4NYRXGUA.

--

OpenChrom - the open source alternative for chromatography / mass spectrometry
Dr. Philip Wenig » Founder » philip.wenig@openchrom.net » http://www.openchrom.net
buchen commented 2 weeks ago

Did this contribution in made it into the code base?

I am asking because the performance of the line charts make me hesitate to move from org.swtchart to org.eclipse.swtchart because the tooltips are visibly jerky ("ruckeln"). I don't really understand what the difference is, but there appears to be a paint event when re-positioning the tooltip. And that paint event is relative slow. I am wondering if such a change as this could help.

eselmeister commented 2 weeks ago

Unfortunately, the code didn't make it into the code base as @ifsarbaby didn't create an official pull request.

eselmeister commented 2 weeks ago

It would be great to speed up the plotting even when using a huge amount of data points.

eselmeister commented 2 weeks ago

@buchen I will inspect the requested changes and try to create a PR to make the charts faster.

buchen commented 2 weeks ago

@eselmeister thanks. After some more investigation, I believe at the moment that the primary problem are additional paint events. This change could make the drawing faster, but I wonder why the paint events occur in the first place: #420