blob: 03d028a4315bc7b8472f95ec17fdb092398701bb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.test.internal.performance.results.db;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import org.eclipse.test.internal.performance.results.utils.Util;
/**
* Class to handle performance results of a component's scenario
* (for example 'org.eclipse.jdt.core.FullSourceWorkspaceSearchTest#searchAllTypeNames()').
*
* It gives access to results for each configuration run on this scenario.
*
* @see ConfigResults
*/
public class ScenarioResults extends AbstractResults {
String fileName;
String label;
String shortName;
public ScenarioResults(int id, String name, String shortName) {
super(null, id);
this.name = name;
this.label = shortName;
}
/*
* Complete results with additional database information.
*/
void completeResults(String lastBuildName) {
String[] builds = DB_Results.getBuilds();
class BuildDateComparator implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
return Util.getBuildDate(s1).compareTo(Util.getBuildDate(s2));
}
}
BuildDateComparator comparator = new BuildDateComparator();
Arrays.sort(builds, comparator);
int idx = Arrays.binarySearch(builds, lastBuildName, comparator);
if (idx < 0) {
builds = null;
} else {
int size = builds.length - ++idx;
System.arraycopy(builds, idx, builds = new String[size], 0, size);
}
// String[] builds = null;
int size = size();
for (int i=0; i<size; i++) {
ConfigResults configResults = (ConfigResults) this.children.get(i);
configResults.completeResults(builds);
}
}
/**
* Returns the first configuration baseline build name.
*
* @return The name of the baseline build
* @see ConfigResults#getBaselineBuildName()
*/
public String getBaselineBuildName() {
int size = size();
StringBuilder buffer = new StringBuilder();
for (int i=0; i<size; i++) {
ConfigResults configResults = (ConfigResults) this.children.get(i);
if (configResults.isValid()) {
return configResults.getBaselineBuildName();
/* TODO (frederic) decide what return when baseline is not the same on all configs...
* Currently returns the first found, but may be a comma-separated list?
String baselineName = configResults.getBaselineBuildName();
if (buffer.indexOf(baselineName) < 0) {
if (buffer.length() > 0) buffer.append('|');
buffer.append(baselineName);
}
*/
}
}
return buffer.toString();
}
Set<String> getAllBuildNames() {
Set<String> buildNames = new HashSet<>();
int size = size();
for (int i=0; i<size; i++) {
ConfigResults configResults = (ConfigResults) this.children.get(i);
List<BuildResults> builds = configResults.getBuilds(null);
int length = builds.size();
for (int j=0; j<length; j++) {
buildNames.add(builds.get(j).getName());
}
}
return buildNames;
}
/**
* Return the results of the given configuration.
*
* @param config The configuration name
* @return The {@link ConfigResults results} for the given configuration
* or <code>null</code> if none was found.
*/
public ConfigResults getConfigResults(String config) {
return (ConfigResults) getResults(config);
}
/**
* Return a name which can be used as a file name to store information
* related to this scenario. This name does not contain the extension.
*
* @return The file name
*/
public String getFileName() {
if (this.fileName == null) {
this.fileName = "Scenario" + this.id; //$NON-NLS-1$
}
return this.fileName;
}
/**
* Returns the scenario label. If no label exist as there's no associated summary,
* then the short name is returned
*
* @return The label of the scenario or it's short name if no summary exists
*/
public String getLabel() {
return this.label == null ? getShortName() : this.label;
}
/**
* Returns the short name of the scenario. Short name is the name scenario
* from which package declaration has been removed.
*
* @return The scenario short name
*/
public String getShortName() {
if (this.shortName == null) {
// Remove class name qualification
int testSeparator = this.name.indexOf('#');
boolean hasClassName = testSeparator >= 0;
if (!hasClassName) {
testSeparator = this.name.lastIndexOf('.');
if (testSeparator <= 0) {
return this.shortName = this.name;
}
}
int classSeparator = this.name.substring(0, testSeparator).lastIndexOf('.');
if (classSeparator < 0) {
return this.shortName = this.name;
}
int length = this.name.length();
String testName = this.name.substring(classSeparator+1, length);
if (!hasClassName && testName.startsWith("test.")) { // specific case for swt... //$NON-NLS-1$
testName = testName.substring(5);
}
// Remove qualification from test name
StringTokenizer tokenizer = new StringTokenizer(testName, " :,", true); //$NON-NLS-1$
StringBuilder buffer = new StringBuilder(tokenizer.nextToken());
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
char fc = token.charAt(0);
while (fc == ' ' || fc == ',' || fc == ':') {
buffer.append(token); // add the separator
token = tokenizer.nextToken();
fc = token.charAt(0);
}
int last = token.lastIndexOf('.');
if (last >= 3) {
int first = token .indexOf('.');
if (first == last) {
buffer.append(token);
} else {
buffer.append(token.substring(last+1));
}
} else {
buffer.append(token);
}
}
this.shortName = buffer.toString();
}
return this.shortName;
}
/**
* Returns whether one of the scenario's config has a summary or not.
*
* @return <code>true</code> if one of the scenario's config has a summary
* <code>false</code> otherwise.
*/
public boolean hasSummary() {
int size = size();
for (int i=0; i<size; i++) {
ConfigResults configResults = (ConfigResults) this.children.get(i);
BuildResults currentBuildResults = configResults.getCurrentBuildResults();
if (currentBuildResults != null && currentBuildResults.hasSummary()) return true;
}
return false;
}
@Override
public int hashCode() {
return this.id;
}
/**
* Returns whether the current scenario is valid or not.
*
* @return <code>true</code> if all the builds contained in the database are
* known by the scenario (ie. at least one its configuration knows each of the
* db builds), <code>false</code> otherwise.
*/
public boolean isValid() {
int size = this.children.size();
for (int i=0; i<size; i++) {
ConfigResults configResults = (ConfigResults) this.children.get(i);
if (configResults.isValid()) {
return true;
}
}
return false;
}
/**
* Returns whether the current build of the given config has valid results or not.
*
* @param config The name of the configuration
* @return <code>true</code> if the build has valid results
* <code>false</code> otherwise.
*/
public boolean isValid(String config) {
return getResults(config) != null;
}
/**
* Returns whether the current scenario knows a build or not.
*
* @param buildName The name of the build
* @return <code>true</code> if the at least one of scenario configuration
* knows the given build, <code>false</code> otherwise.
*/
public boolean knowsBuild(String buildName) {
String[] buildNames = buildName == null
? DB_Results.getBuilds()
: new String[] { buildName };
Set<String> scenarioBuilds = getAllBuildNames();
int length = buildNames.length;
for (int i=0; i<length; i++) {
if (!scenarioBuilds.contains(buildNames[i])) {
return false;
}
}
return true;
}
/*
* Read scenario results information from database.
*
void read(String buildName, long lastBuildTime) {
// Get values
print(" + scenario '"+getShortName()+"': values..."); //$NON-NLS-1$ //$NON-NLS-2$
long start = System.currentTimeMillis();
String configPattern = getPerformance().getConfigurationsPattern();
DB_Results.queryScenarioValues(this, configPattern, buildName, lastBuildTime);
print(timeString(System.currentTimeMillis()-start));
// Set baseline and current builds
print(", infos..."); //$NON-NLS-1$
start = System.currentTimeMillis();
int size = size();
String[] builds = buildName == null ? null : new String[] { buildName };
for (int i=0; i<size; i++) {
ConfigResults configResults = (ConfigResults) this.children.get(i);
configResults.completeResults(builds);
}
println(timeString(System.currentTimeMillis()-start));
}
*/
/*
* Read data from a local file
*/
void readData(DataInputStream stream) throws IOException {
// Read data stored locally
int size = stream.readInt();
for (int i=0; i<size; i++) {
int config_id = stream.readInt();
ConfigResults configResults = (ConfigResults) getResults(config_id);
if (configResults == null) {
configResults = new ConfigResults(this, config_id);
addChild(configResults, true);
}
configResults.readData(stream);
}
}
/*
* Read new data from the database.
* This is typically needed when the build results are not in the local file...
*
boolean readNewData(String lastBuildName, boolean force) {
if (lastBuildName == null) {
read(null, -1);
return true;
}
PerformanceResults performanceResults = getPerformance();
String lastBuildDate = getBuildDate(lastBuildName, getBaselinePrefix());
if (force || performanceResults.getBuildDate().compareTo(lastBuildDate) > 0) {
long lastBuildTime = 0;
try {
lastBuildTime = DATE_FORMAT.parse(lastBuildDate).getTime();
} catch (ParseException e) {
// should not happen
}
read(lastBuildName, lastBuildTime);
return true;
}
return false;
}
*/
/*
* Set value from database information.
*/
void setInfos(int config_id, int build_id, int summaryKind, String comment) {
ConfigResults configResults = (ConfigResults) getResults(config_id);
if (configResults == null) {
configResults = new ConfigResults(this, config_id);
addChild(configResults, true);
}
configResults.setInfos(build_id, summaryKind, comment);
}
/*
* Set value from database information.
*/
void setValue(int build_id, int dim_id, int config_id, int step, long value) {
ConfigResults configResults = (ConfigResults) getResults(config_id);
if (configResults == null) {
configResults = new ConfigResults(this, config_id);
addChild(configResults, true);
}
configResults.setValue(build_id, dim_id, step, value);
}
/*
* Read scenario results information from database.
*/
boolean updateBuild(String buildName, boolean force) {
if (!force && knowsBuild(buildName)) {
return false;
}
// Get values
print(" + scenario '"+getShortName()+"': values..."); //$NON-NLS-1$ //$NON-NLS-2$
long start = System.currentTimeMillis();
String configPattern = getPerformance().getConfigurationsPattern();
DB_Results.queryScenarioValues(this, configPattern, buildName);
print(Util.timeString(System.currentTimeMillis()-start));
// Set baseline and current builds
print(", infos..."); //$NON-NLS-1$
start = System.currentTimeMillis();
int size = size();
String[] builds = buildName == null ? null : new String[] { buildName };
for (int i=0; i<size; i++) {
ConfigResults configResults = (ConfigResults) this.children.get(i);
configResults.completeResults(builds);
}
println(Util.timeString(System.currentTimeMillis()-start));
return true;
}
void write(DataOutputStream stream) throws IOException {
if (DO_NOT_WRITE_DATA) {
return;
}
int size = size();
stream.writeInt(this.id);
stream.writeInt(size);
for (int i=0; i<size; i++) {
ConfigResults configResults = (ConfigResults) this.children.get(i);
configResults.write(stream);
}
}
}