1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/**
25 * @subtest
26 */
27var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__;
28load(dir + "octane-payload.js");
29
30var runtime = undefined;
31var verbose = false;
32
33var numberOfIterations = 5;
34
35function endsWith(str, suffix) {
36    return str.indexOf(suffix, str.length - suffix.length) !== -1;
37}
38
39function should_compile_only(name) {
40    return (typeof compile_only !== 'undefined')
41}
42
43function load_bench(arg) {
44
45    for (var idx = 0; idx < arg.files.length; idx++) {
46        var f = arg.files[idx];
47        var file = f.split('/');
48        var file_name = path + file[file.length - 1];
49
50        var compile_and_return = should_compile_only(file_name);
51        if (compile_and_return) {
52            if (typeof compile_only === 'undefined') { //for a run, skip compile onlies, don't even compile them
53                return true;
54            }
55        }
56
57        print_verbose(arg, "loading '" + arg.name + "' [" + f + "]... " + file_name);
58        load(file_name);
59    }
60
61    if (typeof arg.before !== 'undefined') {
62        arg.before();
63    }
64
65    if (compile_and_return) {
66        print_always(arg, "Compiled OK");
67    }
68    return !compile_and_return;
69
70}
71
72
73function run_one_benchmark(arg, iters) {
74
75    if (!load_bench(arg)) {
76        return;
77    }
78
79    var success = true;
80    var current_name;
81
82    if (iters == undefined) {
83        iters = numberOfIterations;
84    } else {
85        numberOfIterations = iters;
86    }
87
88    var benchmarks = eval(arg.suite + ".benchmarks");
89    var min_score  = 1e9;
90    var max_score  = 0;
91    var mean_score = 0;
92
93    try {
94        for (var x = 0; x < benchmarks.length ; x++) {
95            //do warmup run
96            //reset random number generator needed as of octane 9 before each run
97            BenchmarkSuite.ResetRNG();
98            benchmarks[x].Setup();
99        }
100        BenchmarkSuite.ResetRNG();
101        print_verbose(arg, "running '" + arg.name + "' for " + iters + " iterations of no less than " + min_time + " seconds");
102
103        var scores = [];
104
105        var min_time_ms = min_time * 1000;
106        var len = benchmarks.length;
107
108        for (var it = 0; it < iters + 1; it++) {
109            //every iteration must take a minimum of 10 secs
110            var ops = 0;
111            var elapsed = 0;
112            var start = new Date;
113            do {
114                for (var i = 0; i < len; i++) {
115                    benchmarks[i].run();
116                    //important - no timing here like elapsed = new Date() - start, as in the
117                    //original harness. This will make timing very non-deterministic.
118                    //NOTHING else must live in this loop
119                }
120                ops += len;
121                elapsed = new Date - start;
122            } while (elapsed < min_time * 1000);
123
124            var score = ops / elapsed * 1000 * 60;
125            scores.push(score);
126            var name = it == 0 ? "warmup" : "iteration " + it;
127            print_verbose(arg, name + " finished " + score.toFixed(0) + " ops/minute");
128
129            // optional per-iteration cleanup hook
130            if (typeof arg.cleanUpIteration == "function") {
131                arg.cleanUpIteration();
132            }
133        }
134
135        for (var x = 0; x < benchmarks.length ; x++) {
136            benchmarks[x].TearDown();
137        }
138
139        for (var x = 1; x < iters + 1 ; x++) {
140            mean_score += scores[x];
141            min_score = Math.min(min_score, scores[x]);
142            max_score = Math.max(max_score, scores[x]);
143        }
144        mean_score /= iters;
145    } catch (e) {
146        print_always(arg, "*** Aborted and setting score to zero. Reason: " + e);
147        if (is_this_nashorn() && e instanceof java.lang.Throwable) {
148            e.printStackTrace();
149        }
150        mean_score = min_score = max_score = 0;
151        scores = [0];
152    }
153
154    var res = mean_score.toFixed(0);
155    if (verbose) {
156        res += " ops/minute (" + min_score.toFixed(0) + "-" + max_score.toFixed(0) + "), warmup=" + scores[0].toFixed(0);
157    }
158    print_always(arg, res);
159}
160
161function runtime_string() {
162    return runtime == undefined ? "" : ("[" + runtime + "] ");
163}
164
165function print_always(arg, x) {
166    print(runtime_string() + "[" + arg.name + "] " + x);
167}
168
169function print_verbose(arg, x) {
170    if (verbose) {
171        print_always(arg, x)
172    }
173}
174
175function run_suite(tests, iters) {
176    for (var idx = 0; idx < tests.length; idx++) {
177        run_one_benchmark(tests[idx], iters);
178    }
179}
180
181var args = [];
182
183if (typeof $ARGS !== 'undefined') {
184    args = $ARGS;
185} else if (typeof arguments !== 'undefined' && arguments.length != 0) {
186    args = arguments;
187}
188
189var new_args = [];
190for (i in args) {
191    if (args[i].toString().indexOf(' ') != -1) {
192        args[i] = args[i].replace(/\/$/, '');
193        var s = args[i].split(' ');
194        for (j in s) {
195            new_args.push(s[j]);
196        }
197    } else {
198        new_args.push(args[i]);
199    }
200}
201
202if (new_args.length != 0) {
203    args = new_args;
204}
205
206var tests_found = [];
207var iters = undefined;
208var min_time = 5;
209
210for (var i = 0; i < args.length; i++) {
211    arg = args[i];
212    if (arg == "--iterations") {
213        iters = +args[++i];
214        if (isNaN(iters)) {
215            throw "'--iterations' must be followed by integer";
216        }
217    } else if (arg == "--runtime") {
218        runtime = args[++i];
219    } else if (arg == "--verbose") {
220        verbose = true;
221    } else if (arg == "--min-time") {
222        min_time = +args[++i];
223        if (isNaN(iters)) {
224            throw "'--min-time' must be followed by integer";
225        }
226    } else if (arg == "") {
227        continue; //skip
228    } else {
229        var found = false;
230        for (j in tests) {
231            if (tests[j].name === arg) {
232                tests_found.push(tests[j]);
233                found = true;
234                break;
235            }
236        }
237        if (!found) {
238            var str = "unknown test name: '" + arg + "' -- valid names are: ";
239            for (j in tests) {
240                if (j != 0) {
241                    str += ", ";
242                }
243                str += "'" + tests[j].name + "'";
244            }
245            throw str;
246        }
247    }
248}
249
250if (tests_found.length == 0) {
251    for (i in tests) {
252        tests_found.push(tests[i]);
253    }
254}
255
256// returns false for rhino, v8 and all other javascript runtimes, true for Nashorn
257function is_this_nashorn() {
258    return typeof Error.dumpStack == 'function'
259}
260
261if (is_this_nashorn()) {
262    try {
263        read = readFully;
264    } catch (e) {
265        print("ABORTING: Cannot find 'readFully'. You must have scripting enabled to use this test harness. (-scripting)");
266        throw e;
267    }
268}
269
270// run tests in alphabetical order by name
271tests_found.sort(function(a, b) {
272    if (a.name < b.name) {
273        return -1;
274    } else if (a.name > b.name) {
275        return 1;
276    } else {
277        return 0;
278    }
279});
280
281load(path + 'base.js');
282run_suite(tests_found, iters);
283