| /******************************************************************************* |
| * Copyright (c) 2000, 2020 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(); |
| Comparator<String> comparator = (s1, s2) -> Util.getBuildDate(s1).compareTo(Util.getBuildDate(s2)); |
| 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); |
| } |
| } |
| |
| } |