blob: da7619576b4457ee8d52f5176b491c857cfa42b9 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/*
25 *
26 */
27
28package bench;
29
30import java.io.InputStream;
31import java.io.InputStreamReader;
32import java.io.StreamTokenizer;
33import java.io.IOException;
34import java.util.Vector;
35
36
37/**
38 * Benchmark harness. Responsible for parsing config file and running
39 * benchmarks.
40 */
41public class Harness {
42
43 BenchInfo[] binfo;
44
45 /**
46 * Create new benchmark harness with given configuration and reporter.
47 * Throws ConfigFormatException if there was an error parsing the config
48 * file.
49 * <p>
50 * <b>Config file syntax:</b>
51 * <p>
52 * '#' marks the beginning of a comment. Blank lines are ignored. All
53 * other lines should adhere to the following format:
54 * <pre>
55 * &lt;weight&gt; &lt;name&gt; &lt;class&gt; [&lt;args&gt;]
56 * </pre>
57 * &lt;weight&gt; is a floating point value which is multiplied times the
58 * benchmark's execution time to determine its weighted score. The
59 * total score of the benchmark suite is the sum of all weighted scores
60 * of its benchmarks.
61 * <p>
62 * &lt;name&gt; is a name used to identify the benchmark on the benchmark
63 * report. If the name contains whitespace, the quote character '"' should
64 * be used as a delimiter.
65 * <p>
66 * &lt;class&gt; is the full name (including the package) of the class
67 * containing the benchmark implementation. This class must implement
68 * bench.Benchmark.
69 * <p>
70 * [&lt;args&gt;] is a variable-length list of runtime arguments to pass to
71 * the benchmark. Arguments containing whitespace should use the quote
72 * character '"' as a delimiter.
73 * <p>
74 * <b>Example:</b>
75 * <pre>
76 * 3.5 "My benchmark" bench.serial.Test first second "third arg"
77 * </pre>
78 */
79 public Harness(InputStream in) throws IOException, ConfigFormatException {
80 Vector bvec = new Vector();
81 StreamTokenizer tokens = new StreamTokenizer(new InputStreamReader(in));
82
83 tokens.resetSyntax();
84 tokens.wordChars(0, 255);
85 tokens.whitespaceChars(0, ' ');
86 tokens.commentChar('#');
87 tokens.quoteChar('"');
88 tokens.eolIsSignificant(true);
89
90 tokens.nextToken();
91 while (tokens.ttype != StreamTokenizer.TT_EOF) {
92 switch (tokens.ttype) {
93 case StreamTokenizer.TT_WORD:
94 case '"': // parse line
95 bvec.add(parseBenchInfo(tokens));
96 break;
97
98 default: // ignore
99 tokens.nextToken();
100 break;
101 }
102 }
103 binfo = (BenchInfo[]) bvec.toArray(new BenchInfo[bvec.size()]);
104 }
105
106 BenchInfo parseBenchInfo(StreamTokenizer tokens)
107 throws IOException, ConfigFormatException
108 {
109 float weight = parseBenchWeight(tokens);
110 String name = parseBenchName(tokens);
111 Benchmark bench = parseBenchClass(tokens);
112 String[] args = parseBenchArgs(tokens);
113 if (tokens.ttype == StreamTokenizer.TT_EOL)
114 tokens.nextToken();
115 return new BenchInfo(bench, name, weight, args);
116 }
117
118 float parseBenchWeight(StreamTokenizer tokens)
119 throws IOException, ConfigFormatException
120 {
121 float weight;
122 switch (tokens.ttype) {
123 case StreamTokenizer.TT_WORD:
124 case '"':
125 try {
126 weight = Float.parseFloat(tokens.sval);
127 } catch (NumberFormatException e) {
128 throw new ConfigFormatException("illegal weight value \"" +
129 tokens.sval + "\" on line " + tokens.lineno());
130 }
131 tokens.nextToken();
132 return weight;
133
134 default:
135 throw new ConfigFormatException("missing weight value on line "
136 + tokens.lineno());
137 }
138 }
139
140 String parseBenchName(StreamTokenizer tokens)
141 throws IOException, ConfigFormatException
142 {
143 String name;
144 switch (tokens.ttype) {
145 case StreamTokenizer.TT_WORD:
146 case '"':
147 name = tokens.sval;
148 tokens.nextToken();
149 return name;
150
151 default:
152 throw new ConfigFormatException("missing benchmark name on " +
153 "line " + tokens.lineno());
154 }
155 }
156
157 Benchmark parseBenchClass(StreamTokenizer tokens)
158 throws IOException, ConfigFormatException
159 {
160 Benchmark bench;
161 switch (tokens.ttype) {
162 case StreamTokenizer.TT_WORD:
163 case '"':
164 try {
165 Class cls = Class.forName(tokens.sval);
166 bench = (Benchmark) cls.newInstance();
167 } catch (Exception e) {
168 throw new ConfigFormatException("unable to instantiate " +
169 "benchmark \"" + tokens.sval + "\" on line " +
170 tokens.lineno());
171 }
172 tokens.nextToken();
173 return bench;
174
175 default:
176 throw new ConfigFormatException("missing benchmark class " +
177 "name on line " + tokens.lineno());
178 }
179 }
180
181 String[] parseBenchArgs(StreamTokenizer tokens)
182 throws IOException, ConfigFormatException
183 {
184 Vector vec = new Vector();
185 for (;;) {
186 switch (tokens.ttype) {
187 case StreamTokenizer.TT_EOF:
188 case StreamTokenizer.TT_EOL:
189 return (String[]) vec.toArray(new String[vec.size()]);
190
191 case StreamTokenizer.TT_WORD:
192 case '"':
193 vec.add(tokens.sval);
194 tokens.nextToken();
195 break;
196
197 default:
198 throw new ConfigFormatException("unrecognized arg token " +
199 "on line " + tokens.lineno());
200 }
201 }
202 }
203
204 /**
205 * Run benchmarks, writing results to the given reporter.
206 */
207 public void runBenchmarks(Reporter reporter, boolean verbose) {
208 for (int i = 0; i < binfo.length; i++) {
209 if (verbose)
210 System.out.println("Running benchmark " + i + " (" +
211 binfo[i].getName() + ")");
212 try {
213 binfo[i].runBenchmark();
214 } catch (Exception e) {
215 System.err.println("Error: benchmark " + i + " failed: " + e);
216 e.printStackTrace();
217 }
218 cleanup();
219 }
220 try {
221 reporter.writeReport(binfo, System.getProperties());
222 } catch (IOException e) {
223 System.err.println("Error: failed to write benchmark report");
224 }
225 }
226
227 /**
228 * Clean up method that is invoked after the completion of each benchmark.
229 * The default implementation calls System.gc(); subclasses may override
230 * this to perform additional cleanup measures.
231 */
232 protected void cleanup() {
233 System.gc();
234 }
235}