Community
Participate
Working Groups
The time required to draw line/stock charts using large datasets(1500 data points) takes about 3 seconds. This is obviously an optimization issue on the graph rendering side. This problem makes it impossible to use multiple charts in an RCP enviroment, because resizing the chart causes a chain reaction for refreshing (3 seconds for each chart).
Please specify with which version of BIRT this is happening and which device renderer you're using. Thanks
im currently using S20051110. Im using the SWT device renderer. (In reply to comment #1) > Please specify with which version of BIRT this is happening and which device > renderer you're using. Thanks >
Do you show the X Axis labels or not? Have you tried turning their visibility to off? The code that auto-drops them introduces an overload in the chart generation process.
Yes I have tried that. The performance does improve margiannaly. A huge delay in redrawing the graph still exists, making it unusable.
That's strange, an instrumentation shows 90% of time spent in there, making them invisble should have increased the performance a lot. Maybe there is some other problem, are you using -DR31ENHANCE=1? This can also be a performance issue, since it's using reflection to keep the SWT 3.0 compatibility. Can you send me your chart design, or the API code to create the chart? maybe there is some specific settings you have set that introduced that problem.
Instrumentation shows that without X Axis labels, 50% of time is spent by the EMF model doing copies, creation, set, get, more precisely on the LocationImpl and ColorDefinitionImpl objects. These objects are being used for computations and rendering, which is wrong, they should first be converted to lightweight java objects due to their intensive usage. However this means a major change throughout the chart engine, so this is an enhancement for a future version The remaining of the time is evenly distributed among generation, internal computations and rendering of the chart. Besides that I will optimize the X Axis labels auto-drop algorithm to be about twice faster. To complete it we could provide more control in the future to manually force the dropping through the API/model, for instance by showing only one label out of n labels, where can be configured in the model.
I have checked in this X-Axis labels optimization. I now propose to defer this performance enhancement to a future release. Possible work-around in the meantime for the reporter: - Reduce the number of points in your dataset, this won't affect the chart drawing quality, you should be able to get a nice looking chart with only a few hundreds points (or even less) and by selecting show lines as curves. - Hide the ticks on the X-Axis, Hide the labels on the X-Axis
Replaced some of the EcoreUtil.copy() with custom copyInstance() method, so chart building/rendering should be faster now. But still need further thoughts to reduce the EMF performance impact.
Mark as fixed.
Redrawing a graph with 1500 data points is still taking a fair amount of time on BIRT 2.3.0. While it doesn't appear to be taking three seconds on my computer, which is what Evangelos originally stated, it is still too slow in my opinion. We are working on an RCP product that grabs the polled statistics from a machine and renders it for the administrator. If you consider a poll rate of one per second, a whole day's statistic will have 86,400 points. ------------------- The statistics below were retrieved from running the LargeDataSet class below and then trying to resize it. It seems the initial drawing procedure takes more time than subsequent redraws but it is still not fast enough. Max set at 1500: Rendering Time: 2451 Rendering Time: 1233 Rendering Time: 1093 Max set at 5000: Rendering Time: 4903 Rendering Time: 3638 Rendering Time: 3451 Rendering Time: 3498 Max set at 10000: Rendering Time: 9368 Rendering Time: 6964 Rendering Time: 6839 ------------------- import java.util.List; import org.eclipse.birt.chart.api.ChartEngine; import org.eclipse.birt.chart.device.IDeviceRenderer; import org.eclipse.birt.chart.exception.ChartException; import org.eclipse.birt.chart.factory.GeneratedChartState; import org.eclipse.birt.chart.factory.Generator; import org.eclipse.birt.chart.model.ChartWithAxes; import org.eclipse.birt.chart.model.attribute.Bounds; import org.eclipse.birt.chart.model.attribute.Marker; import org.eclipse.birt.chart.model.attribute.impl.BoundsImpl; import org.eclipse.birt.chart.model.attribute.impl.ColorDefinitionImpl; import org.eclipse.birt.chart.model.component.Axis; import org.eclipse.birt.chart.model.component.Series; import org.eclipse.birt.chart.model.component.impl.SeriesImpl; import org.eclipse.birt.chart.model.data.DataSet; import org.eclipse.birt.chart.model.data.SeriesDefinition; import org.eclipse.birt.chart.model.data.impl.NumberDataSetImpl; import org.eclipse.birt.chart.model.data.impl.SeriesDefinitionImpl; import org.eclipse.birt.chart.model.impl.ChartWithAxesImpl; import org.eclipse.birt.chart.model.type.LineSeries; import org.eclipse.birt.chart.model.type.impl.LineSeriesImpl; import org.eclipse.birt.core.framework.PlatformConfig; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; class LargeDataSet extends Composite implements PaintListener { private IDeviceRenderer deviceRenderer; private ChartWithAxes chart; private GeneratedChartState chartState; private SeriesDefinition sdX; private SeriesDefinition sdY; private Image imgChart; private GC gcImage; LargeDataSet(Composite parent, int style) { super(parent, style); try { PlatformConfig config = new PlatformConfig(); config.setProperty("STANDALONE", "true"); //$NON-NLS-1$ //$NON-NLS-2$ deviceRenderer = ChartEngine.instance(config).getRenderer("dv.SWT");//$NON-NLS-1$ } catch (ChartException pex) { pex.printStackTrace(); System.exit(0); } chart = ChartWithAxesImpl.create(); // X-Axis Axis xAxisPrimary = chart.getPrimaryBaseAxes()[0]; // X-Series sdX = SeriesDefinitionImpl.create(); xAxisPrimary.getSeriesDefinitions().add(sdX); // Y-Axis Axis yAxisPrimary = chart.getPrimaryOrthogonalAxis(xAxisPrimary); // Y-Series sdY = SeriesDefinitionImpl.create(); yAxisPrimary.getSeriesDefinitions().add(sdY); sdY.getSeriesPalette().shift(-1); addPaintListener(this); addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { if (imgChart != null) { imgChart.dispose(); } if (gcImage != null) { gcImage.dispose(); } } }); } public static void main(String[] args) { Display display = Display.getDefault(); final Shell shell = new Shell(display); shell.setLayout(new FillLayout()); shell.setSize(640, 480); LargeDataSet adbv = new LargeDataSet(shell, SWT.NO_BACKGROUND); int MAX = 1500; double[] times = new double[MAX]; double[] values = new double[MAX]; for (int i = 0; i < MAX; i++) { times[i] = System.currentTimeMillis() + i; values[i] = i; } adbv.initializeGraph(times, values); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } private void initializeGraph(double[] timeArray, double[] statisticValues) { DataSet xDataSet = NumberDataSetImpl.create(timeArray); Series xSeries = SeriesImpl.create(); xSeries.setDataSet(xDataSet); sdX.getSeries().add(xSeries); DataSet yDataSet = NumberDataSetImpl.create(statisticValues); LineSeries ySeries = (LineSeries) LineSeriesImpl.create(); ySeries.setDataSet(yDataSet); ySeries.getLineAttributes().setColor(ColorDefinitionImpl.BLACK()); List markers = ySeries.getMarkers(); for (Object object : markers) { Marker marker = (Marker) object; marker.setVisible(false); } sdY.getSeries().add(ySeries); } public void paintControl(PaintEvent e) { long l = System.currentTimeMillis(); if (gcImage != null) { gcImage.dispose(); } if (imgChart != null) { imgChart.dispose(); } Rectangle d = getClientArea(); imgChart = new Image(getDisplay(), d); gcImage = new GC(imgChart); deviceRenderer.setProperty(IDeviceRenderer.GRAPHICS_CONTEXT, gcImage); Bounds bo = BoundsImpl.create(0, 0, d.width, d.height); bo.scale(72d / deviceRenderer.getDisplayServer().getDpiResolution()); Generator gr = Generator.instance(); try { chartState = gr.build(deviceRenderer.getDisplayServer(), chart, bo, null, null, null); gr.render(deviceRenderer, chartState); e.gc.drawImage(imgChart, d.x, d.y); l = System.currentTimeMillis() - l; System.out.println("Rendering Time:\t" + l); } catch (ChartException ce) { ce.printStackTrace(); } } }
Zhiqiang, Shall we consider this enh idea from David in comment #6? "Instrumentation shows that without X Axis labels, 50% of time is spent by the EMF model doing copies, creation, set, get, more precisely on the LocationImpl and ColorDefinitionImpl objects. These objects are being used for computations and rendering, which is wrong, they should first be converted to lightweight java objects due to their intensive usage. However this means a major change throughout the chart engine, so this is an enhancement for a future version"
Yes, we can consider using more plain java objects instead of EMF objects for the computation. We already did some similar things for the Axis model.
Many optimization are made to accelerate Chart graphics, especially for chart with large dataset, noteworthy are the followings: - accelerated the formatting of axis labels - accelerated the computation of labels bounding - accelerated the copying of some EMF Object, i.e. Fill, Marker - accelerated the set operation of some EMF Object, i.e. Location, Bounds - accelerated the rendering of axis ticks for large dataset - reduced memory usage of AutoScale for large dataset The performance is improved dramatically, the same test with LargeDataSet and 5000 data points are made for both the previous version and the new version, see below: Max set at 5000: previous -------------------- Rendering Time: 8547 Rendering Time: 7219 Rendering Time: 7016 Rendering Time: 7047 now -------------------- Rendering Time: 2218 Rendering Time: 890 Rendering Time: 656 Rendering Time: 422
Verified in BIRT2.5.0 (daily build 090105)