View Javadoc

1   /*
2    * DaCapo Benchmark Maven Plugin
3    * Copyright (C) 2010 Technische Universität Darmstadt
4    * info@scalabench.org
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.scalabench.plugins.dacapo;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.LinkedList;
25  import java.util.List;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.execution.MavenSession;
29  import org.apache.maven.plugin.MojoExecutionException;
30  import org.apache.maven.plugin.MojoFailureException;
31  import org.apache.maven.toolchain.Toolchain;
32  import org.apache.maven.toolchain.ToolchainManager;
33  import org.codehaus.plexus.util.FileUtils;
34  import org.codehaus.plexus.util.StringUtils;
35  import org.codehaus.plexus.util.cli.CommandLineException;
36  import org.codehaus.plexus.util.cli.CommandLineUtils;
37  import org.codehaus.plexus.util.cli.Commandline;
38  import org.dacapo.parser.Config;
39  import org.scalabench.dacapo.callback.XmlSummaryCallback;
40  import org.scalabench.plugins.dacapo.util.SizeNameComparator;
41  import org.sonatype.aether.RepositorySystem;
42  import org.sonatype.aether.RepositorySystemSession;
43  import org.sonatype.aether.collection.CollectRequest;
44  import org.sonatype.aether.graph.Dependency;
45  import org.sonatype.aether.repository.RemoteRepository;
46  import org.sonatype.aether.resolution.ArtifactRequest;
47  import org.sonatype.aether.resolution.ArtifactResolutionException;
48  import org.sonatype.aether.resolution.ArtifactResult;
49  import org.sonatype.aether.resolution.DependencyRequest;
50  import org.sonatype.aether.resolution.DependencyResolutionException;
51  import org.sonatype.aether.resolution.DependencyResult;
52  import org.sonatype.aether.util.artifact.DefaultArtifact;
53  
54  /**
55   * Perform sanity checks for integration testing.
56   * 
57   * Note: This goal only runs the benchmarks (possibly for multiple invocations/iterations).
58   * 
59   * @since 0.1.0
60   * 
61   * @threadSafe
62   * @goal integration-test
63   * @phase integration-test
64   * @requiresDependencyResolution runtime
65   */
66  public class IntegrationTestMojo extends AbstractIntegrationTestMojo {
67      
68      /**
69       * The directory where the generated configuration file will be put.
70       * 
71       * @required
72       * @readonly
73       * @parameter expression="${project.build.outputDirectory}/cnf"
74       */
75      private File configurationDirectory;
76      
77      /**
78       * The number of invocations to perform for each benchmark size.
79       * 
80       * @parameter default-value=1
81       */
82      private int testInvocations;
83      
84      /**
85       * The number of iterations to perform for each invocation.
86       * 
87       * @parameter default-value=1
88       */
89      private int testIterations;
90      
91      /**
92       * The summary file to write integration test results to.
93       * 
94       * @parameter default-value="${project.build.directory}/dacapo-benchmark-reports/dacapo-benchmark-summary.xml"
95       */
96      private File summaryFile;
97      
98      /**
99       * The entry point to Aether.
100      * 
101      * @component
102      */
103     private RepositorySystem repoSystem;
104     
105     /**
106      * The current repository/network configuration of Maven.
107      * 
108      * @readonly
109      * @parameter default-value="${repositorySystemSession}"
110      */
111     private RepositorySystemSession repoSession;
112     
113     /**
114      * The project's remote repositories to use for the resolution of plugins
115      * and their dependencies.
116      * 
117      * @readonly
118      * @parameter default-value="${project.remotePluginRepositories}"
119      */
120     private List<RemoteRepository> remoteRepos;
121     
122     /**
123      * The entry point to Maven's toolchain support.
124      * 
125      * @component
126      */
127     private ToolchainManager toolchainManager;
128     
129     /**
130      * The current build session instance. This is used for toolchain manager
131      * API calls.
132      *
133      * @required
134      * @readonly
135      * @parameter expression="${session}"
136      */
137     private MavenSession session;
138     
139     private static final DefaultArtifact CALLBACK_ARTIFACT =
140         new DefaultArtifact("org.scalabench.dacapo", "dacapo-benchmark-callback", "jar", "0.1.0-SNAPSHOT");
141     
142     public File getConfigurationFile() {
143         return new File(getConfigurationDirectory(), getBenchmarkName() + ".cnf");
144     }
145     
146     public File getConfigurationDirectory() {
147         return configurationDirectory;
148     }
149     
150     public int getTestInvocations() {
151         return testInvocations;
152     }
153     
154     public int getTestIterations() {
155         return testIterations;
156     }
157     
158     public File getSummaryFile() {
159         return summaryFile;
160     }
161     
162     @Override
163     public void execute() throws MojoExecutionException, MojoFailureException {
164         if (isSkipExecution()) {
165             logInfo("Tests are skipped.");
166         } else {
167             integrationTestBenchmark();
168         }
169     }
170     
171     private void integrationTestBenchmark() throws MojoExecutionException, MojoFailureException {
172         final String javaExecutable = getJavaExecutable();
173         final Config config = Config.parse(getConfigurationFile());
174         final List<String> sizes = new LinkedList<String>(config.getSizes());
175         
176         Collections.sort(sizes, new SizeNameComparator());
177         
178         for (final String size : sizes) {
179             for (int invocation = 1; invocation <= getTestInvocations(); invocation++) {
180                 logInfo("Running %4$d iterations with input size \"%1$s\" (invocation %2$d of %3$d)",
181                         size, invocation, getTestInvocations(), getTestIterations());
182                 performInvocation(javaExecutable, size);
183             }
184         }
185     }
186     
187     private String getJavaExecutable() throws MojoExecutionException {
188         String javaExecutable;
189         
190         if ((javaExecutable = getJavaPathFromBuildContext()) != null) {
191             logInfo("Selected toolchain (JDK) from build context: %s", javaExecutable);
192             return javaExecutable;
193         } else if ((javaExecutable = getDefaultJavaPath()) != null) {
194             logInfo("Selected default toolchain (JDK): %s", javaExecutable);
195             return javaExecutable;
196         } else {
197             throw new MojoExecutionException("Unable to locate toolchain (JDK)");
198         }
199     }
200     
201     private String getJavaPathFromBuildContext() {
202         final Toolchain toolchain = toolchainManager.getToolchainFromBuildContext("jdk", session);
203         return toolchain == null ? null : toolchain.findTool("java");
204     }
205     
206     private String getDefaultJavaPath() {
207         final String javaHome = System.getProperty("java.home");
208         return javaHome == null ? null : javaHome + File.separator + "bin" + File.separator + "java";
209     }
210     
211     private void performInvocation(String javaExecutable, String size) throws MojoExecutionException, MojoFailureException {
212         final File workingDirectory = createWorkingDirectory(size);
213         logDebug("Created working directory: %s", workingDirectory);
214         
215         try {
216             final Commandline cl = createCommandLine(javaExecutable, workingDirectory, size);
217             logDebug("Forking command line: %s ",  cl);
218             CommandLineUtils.executeCommandLine(cl, null, null, 0);
219         } catch (CommandLineException e) {
220             throw new MojoFailureException("Forked process failed", e);
221         } finally {
222             deleteWorkingDirectory(workingDirectory);
223         }
224     }
225     
226     private File createWorkingDirectory(String size) throws MojoFailureException {
227         final File workingDirectory = FileUtils.createTempFile(getBenchmarkName(), size, null);
228         
229         if (!workingDirectory.mkdir())
230             throw new MojoFailureException("Cannot create working directory: " + workingDirectory);
231         
232         return workingDirectory;
233     }
234     
235     private void deleteWorkingDirectory(File workingDirectory) throws MojoFailureException {
236         try {
237             FileUtils.deleteDirectory(workingDirectory);
238         } catch (IOException e) {
239             throw new MojoFailureException("Cannot delete working directory", e);
240         }
241     }
242     
243     private Commandline createCommandLine(String javaExecutable, File workingDirectory, String size)
244             throws MojoFailureException {
245         final Commandline commandLine = new Commandline();
246         
247         commandLine.setExecutable(javaExecutable);
248         commandLine.setWorkingDirectory(workingDirectory);
249         commandLine.addArguments(new String[] {
250                 "-D" + XmlSummaryCallback.SUMMARY_FILE_PROPERTY + "=" + getSummaryFile(),
251                 "-classpath", StringUtils.join(getRuntimeClasspath().iterator(), File.pathSeparator),
252                 "Harness",
253                 getBenchmarkName(),
254                 "--size", size,
255                 "--iterations", Integer.toString(getTestIterations()),
256                 "--callback", XmlSummaryCallback.class.getName()
257         });
258         
259         return commandLine;
260     }
261     
262     private ArrayList<File> getRuntimeClasspath() throws MojoFailureException {
263         final ArrayList<File> classpath = new ArrayList<File>();
264         
265         classpath.addAll(getProjectClasspath());
266         classpath.addAll(getCallbackClasspath());
267         
268         return classpath;
269     }
270     
271     private List<File> getProjectClasspath() {
272         final List<File> projectClasspath = new ArrayList<File>();
273         
274         projectClasspath.add(getProject().getArtifact().getFile());
275         
276         for (final Artifact artifact : getProject().getArtifacts())
277             projectClasspath.add(artifact.getFile());
278         
279         return projectClasspath;
280     }
281     
282     private List<File> getCallbackClasspath() throws MojoFailureException {
283         try {
284             final List<File> callbackClasspath = new ArrayList<File>();
285             
286             callbackClasspath.add(getCallbackArtifactFile());
287             callbackClasspath.addAll(getCallbackDependencyFiles());
288             
289             return callbackClasspath;
290         } catch (DependencyResolutionException e) {
291             throw new MojoFailureException("Cannot construct classpath for benchmark callback", e);
292         } catch (ArtifactResolutionException e) {
293             throw new MojoFailureException("Cannot construct classpath for benchmark callback", e);
294         }
295     }
296     
297     private File getCallbackArtifactFile() throws ArtifactResolutionException {
298         final ArtifactRequest request = new ArtifactRequest(CALLBACK_ARTIFACT, remoteRepos, null);
299         final ArtifactResult result = repoSystem.resolveArtifact(repoSession, request);
300         return result.getArtifact().getFile();
301     }
302     
303     private List<File> getCallbackDependencyFiles() throws DependencyResolutionException {
304         final Dependency callbackDependency = new Dependency(CALLBACK_ARTIFACT, Artifact.SCOPE_RUNTIME);
305         final DependencyRequest request = new DependencyRequest(new CollectRequest(callbackDependency, remoteRepos), null);
306         final DependencyResult results = repoSystem.resolveDependencies(repoSession, request);
307         final List<File> dependencyFiles = new ArrayList<File>();
308         
309         for (final ArtifactResult artifactResult : results.getArtifactResults())
310             dependencyFiles.add(artifactResult.getArtifact().getFile());
311         
312         return dependencyFiles;
313     }
314 }