blob: 5134340db0b0b272bcb302832732b8ff95707946 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 Mia-Software.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nicolas Bros (Mia-Software) - Bug 343155 - Java discoverer time benchmark
*******************************************************************************/
package org.eclipse.modisco.java.discoverer.benchmark.template.html;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.eclipse.birt.chart.computation.Point;
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.Anchor;
import org.eclipse.birt.chart.model.attribute.AxisType;
import org.eclipse.birt.chart.model.attribute.Bounds;
import org.eclipse.birt.chart.model.attribute.ChartDimension;
import org.eclipse.birt.chart.model.attribute.LineAttributes;
import org.eclipse.birt.chart.model.attribute.LineStyle;
import org.eclipse.birt.chart.model.attribute.impl.BoundsImpl;
import org.eclipse.birt.chart.model.attribute.impl.ColorDefinitionImpl;
import org.eclipse.birt.chart.model.attribute.impl.LineAttributesImpl;
import org.eclipse.birt.chart.model.attribute.impl.NumberFormatSpecifierImpl;
import org.eclipse.birt.chart.model.attribute.impl.TextImpl;
import org.eclipse.birt.chart.model.component.Axis;
import org.eclipse.birt.chart.model.component.Label;
import org.eclipse.birt.chart.model.component.Series;
import org.eclipse.birt.chart.model.component.impl.LabelImpl;
import org.eclipse.birt.chart.model.component.impl.SeriesImpl;
import org.eclipse.birt.chart.model.data.NumberDataSet;
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.layout.LabelBlock;
import org.eclipse.birt.chart.model.layout.impl.LabelBlockImpl;
import org.eclipse.birt.chart.model.type.LineSeries;
import org.eclipse.birt.chart.model.type.ScatterSeries;
import org.eclipse.birt.chart.model.type.impl.LineSeriesImpl;
import org.eclipse.birt.chart.model.type.impl.ScatterSeriesImpl;
import org.eclipse.birt.chart.util.PluginSettings;
import org.eclipse.emf.common.util.EList;
import org.eclipse.modisco.infra.discovery.benchmark.AveragedMultiDiscoveryBenchmark;
import org.eclipse.modisco.infra.discovery.benchmark.AveragedProjectDiscovery;
import org.eclipse.modisco.infra.discovery.benchmark.Project;
public final class BirtGraphHelper {
private static final double CHART_UNIT_SPACING = 0.1;
public static final double MEBIBYTE = 1024.0 * 1024.0;
private BirtGraphHelper() {
//
}
public static void createBirtGraph(final AveragedMultiDiscoveryBenchmark benchmark,
final File targetFolder) throws ChartException {
ChartWithAxes chart = ChartWithAxesImpl.create();
chart.setDimension(ChartDimension.TWO_DIMENSIONAL_LITERAL);
chart.setUnitSpacing(BirtGraphHelper.CHART_UNIT_SPACING);
chart.getPlot().setBackground(ColorDefinitionImpl.WHITE());
chart.getPlot().getClientArea().setBackground(ColorDefinitionImpl.WHITE());
// chart.getLegend().setItemType(LegendItemType.SERIES_LITERAL);
chart.getLegend().setVisible(false);
// TODO: externalize
chart.getTitle().getLabel().getCaption()
.setValue("Discovery time as function of project size"); //$NON-NLS-1$
Axis xAxis = chart.getPrimaryBaseAxes()[0];
xAxis.setType(AxisType.LINEAR_LITERAL);
xAxis.setFormatSpecifier(NumberFormatSpecifierImpl.create());
// TODO: externalize
xAxis.getTitle().getCaption().setValue("Project size (MiB)"); //$NON-NLS-1$
xAxis.getTitle().setVisible(true);
List<Point> dataPoints = new ArrayList<Point>();
for (AveragedProjectDiscovery discovery : benchmark.getDiscoveries()) {
EList<Project> projects = discovery.getOccurrences().get(0).getProjects();
long totalSizeInBytes = 0;
for (Project project : projects) {
totalSizeInBytes += project.getTotalSizeInBytes();
}
dataPoints.add(new Point(totalSizeInBytes / BirtGraphHelper.MEBIBYTE, discovery
.getAverageExecutionTimeInSeconds()));
}
// sort on X axis
Collections.sort(dataPoints, new Comparator<Point>() {
public int compare(final Point o1, final Point o2) {
if (o1.x == o2.x) {
return 0;
} else if (o1.x < o2.x) {
return -1;
} else {
return 1;
}
}
});
ArrayList<Double> xAxisValues = new ArrayList<Double>();
for (Point dataPoint : dataPoints) {
xAxisValues.add(dataPoint.x);
}
NumberDataSet xAxisDataSet = NumberDataSetImpl.create(xAxisValues);
Series xAxisSeries = SeriesImpl.create();
xAxisSeries.setDataSet(xAxisDataSet);
SeriesDefinition xSeriesDefinition = SeriesDefinitionImpl.create();
xSeriesDefinition.getSeries().add(xAxisSeries);
xAxis.getSeriesDefinitions().add(xSeriesDefinition);
Axis yAxis = chart.getPrimaryOrthogonalAxis(xAxis);
yAxis.setType(AxisType.LINEAR_LITERAL);
yAxis.setFormatSpecifier(NumberFormatSpecifierImpl.create());
yAxis.getTitle().setVisible(true);
// TODO: externalize
yAxis.getTitle().getCaption().setValue("Discovery time (seconds)"); //$NON-NLS-1$
ScatterSeries lineSeries = (ScatterSeries) ScatterSeriesImpl.create();
ArrayList<Double> yAxisValues = new ArrayList<Double>();
for (Point dataPoint : dataPoints) {
yAxisValues.add(dataPoint.y);
}
NumberDataSet dataSet = NumberDataSetImpl.create(yAxisValues);
lineSeries.setDataSet(dataSet);
LineAttributes lineAttr = LineAttributesImpl.create(ColorDefinitionImpl.BLACK(),
LineStyle.SOLID_LITERAL, 1);
lineAttr.setVisible(false);
lineSeries.setLineAttributes(lineAttr);
Point[] linearRegression = computeLinearRegression(dataPoints);
LineSeries linearRegressionSeries = (LineSeries) LineSeriesImpl.create();
ArrayList<Double> regressionYAxisValues = new ArrayList<Double>();
for (Point point : linearRegression) {
regressionYAxisValues.add(point.y);
}
NumberDataSet linearRegressionDataSet = NumberDataSetImpl.create(regressionYAxisValues);
linearRegressionSeries.setDataSet(linearRegressionDataSet);
linearRegressionSeries.getMarkers().clear();
// line attributes
LineAttributes lineAttr2 = LineAttributesImpl.create(ColorDefinitionImpl.BLACK(),
LineStyle.DASHED_LITERAL, 1);
lineAttr2.setVisible(true);
linearRegressionSeries.setLineAttributes(lineAttr2);
// display s/MiB
Point lastPoint = linearRegression[linearRegression.length - 1];
LabelBlock labelBlock = (LabelBlock) LabelBlockImpl.create();
Label label = LabelImpl.create();
label.setCaption(TextImpl.create(String.format("%.3f s/MiB", lastPoint.y / lastPoint.x))); //$NON-NLS-1$
labelBlock.setLabel(label);
labelBlock.setAnchor(Anchor.NORTH_EAST_LITERAL);
chart.getPlot().add(labelBlock);
SeriesDefinition ySeriesDefinition = SeriesDefinitionImpl.create();
ySeriesDefinition.getSeries().add(lineSeries);
ySeriesDefinition.getSeries().add(linearRegressionSeries);
yAxis.getSeriesDefinitions().add(ySeriesDefinition);
PluginSettings ps = PluginSettings.instance();
IDeviceRenderer render = ps.getDevice("dv.PNG"); //$NON-NLS-1$
render.setProperty(IDeviceRenderer.FILE_IDENTIFIER, new File(targetFolder,
"executionTimeByProjectSize.png")); //$NON-NLS-1$
final int width = 800;
final int height = 400;
Bounds bounds = BoundsImpl.create(0, 0, width, height);
Generator generator = Generator.instance();
GeneratedChartState state = generator.build(render.getDisplayServer(), chart, bounds, null,
null, null);
generator.render(render, state);
}
/**
* Computes the linear regression of the given list of points, and returns
* points on the computed line.
*
* @param dataPoints
* the points to include in the computation
* @return points on the computed approximation line, with the same abscissa
* as the input points
*/
private static Point[] computeLinearRegression(final List<Point> dataPoints) {
// see: http://en.wikipedia.org/wiki/Simple_linear_regression
double size = dataPoints.size();
if ((int) size == 0) {
return new Point[0];
}
if ((int) size == 1) {
Point point = dataPoints.get(0);
return new Point[] { new Point(point.x, point.y) };
}
double sumXY = 0.0;
double sumX = 0.0;
double sumY = 0.0;
double sumXX = 0.0;
for (Point point : dataPoints) {
sumX += point.x;
sumXX += point.x * point.x;
sumY += point.y;
sumXY += point.x * point.y;
}
// a = (NΣXY - (ΣX)(ΣY)) / (NΣX² - (ΣX)²)
double a = (size * sumXY - sumX * sumY) / (size * sumXX - sumX * sumX);
// b = (ΣY - b(ΣX)) / N
double b = (sumY - a * sumX) / size;
List<Point> resultPoints = new ArrayList<Point>();
for (Point point : dataPoints) {
// y = ax + b
resultPoints.add(new Point(point.x, a * point.x + b));
}
return resultPoints.toArray(new Point[resultPoints.size()]);
}
}