runsunspider.js revision 842:75e8d1a4ba23
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 * runsunspider : runs the sunspider tests and checks for compliance
26 *
27 * @test
28 * @option -timezone=PST
29 * @runif external.sunspider
30 */
31
32/**
33 * This is not a test, but a test "framework" for running sunspider tests.
34 */
35
36function assertEq(a, b) {
37    if (a !== b) {
38        throw "ASSERTION FAILED: " + a + " should be " + b;
39    }
40}
41
42function pprint(x) {
43    if (verbose_run) {
44	print(x);
45    }
46}
47
48var runs = 0;
49var total_time = 0;
50
51function runbench(name) {
52    var filename = name.split("/").pop();
53    pprint("Running (warmup/sanity) " + filename);
54
55    var start = new Date;
56    load(name);
57    var stop = new Date - start;
58    total_time += stop;
59
60    pprint(filename + " done in " + stop + " ms");
61    runs++;
62}
63
64var m_w;
65var m_z;
66var MAXINT;
67
68//produce deterministic random numbers for test suite
69function pseudorandom() {
70    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
71    m_w = 18000 * (m_w & 65535) + (m_w >> 16);
72    return (Math.abs((m_z << 16) + m_w) & MAXINT) / MAXINT;
73}
74
75function initrandom() {
76    m_w = 4711;
77    m_z = 17;
78    MAXINT = 0x7fffffff;
79    Math.random = pseudorandom;
80}
81
82var rtimes = 0;
83var dir = (typeof(__DIR__) == 'undefined') ? "test/script/basic/" : __DIR__;
84var single;
85var verbose_run = false;
86
87var args = [];
88if (typeof $ARGS !== 'undefined') {
89    args = $ARGS;
90} else if (typeof arguments !== 'undefined' && arguments.length != 0) {
91    args = arguments;
92}
93
94for (var i = 0; i < args.length; i++) {
95    if (args[i] === '--verbose') {
96        verbose_run = true;
97    } else if (args[i] === '--times') {
98	i++;
99	rtimes = +args[i];
100    } else if (args[i] === '--single') {
101	i++;
102	single = args[i];
103    }
104}
105
106function runsuite(tests) {
107    var changed   = false;
108    var res       = [];
109    var oldRandom = Math.random;
110
111    try {
112	for (var n = 0; n < tests.length; n++) {
113            path = dir + '../external/sunspider/tests/sunspider-1.0.2/' + tests[n].name
114
115	    initrandom();
116
117	    var dd = new Date;
118
119            runbench(path);
120            if (typeof tests[n].actual !== 'undefined') {
121                assertEq(tests[n].actual(), tests[n].expected());
122            }
123
124	    if (typeof tests[n].rerun !== 'undefined' && tests[n].times > 0) {
125		pprint("rerunning " + tests[n].name + " " + tests[n].times + " times...");
126		var times = 0;
127		var to = tests[n].times;
128
129		var elemsPerPercent = to / 100;
130		var po = 0|(to / 10);
131
132		times = 0;
133		for (; times < to; times++) {
134		    initrandom();
135		    tests[n].rerun();
136		    if ((times % (po|0)) == 0) {
137			pprint(times/to * 100 + "%");
138		    }
139		}
140	    }
141
142	    var t = new Date - dd;
143	    pprint("time: " + t + " ms");
144	    if (typeof tests[n].actual !== 'undefined') {
145		assertEq(tests[n].actual(), tests[n].expected());
146	    }
147	    res.push(t);
148
149	    pprint("");
150
151            changed = true;
152        }
153    } catch (e) {
154	print("FAIL!");
155	throw e;
156        // no scripting or something, silently fail
157    } finally {
158	Math.random = oldRandom;
159    }
160
161    for (var n = 0; n < tests.length; n++) {
162
163	var time = "" + res[n];
164	while (time.length < 4) {
165	    time = " " + time;
166	}
167	time += " ms";
168	if (res[n] == -1) {
169	    time = "<couldn't be rerun>";
170	}
171	var str = tests[n].name;
172	for (var spaces = str.length; spaces < 32; spaces++) {
173	    str += " ";
174	}
175	str += " ";
176	str += time;
177
178	if (tests[n].times > 0) {
179	    str += " [";
180	    str += tests[n].times + " reruns]";
181	}
182	pprint(str);
183    }
184
185    return changed;
186}
187
188function hash(str) {
189    var s = "" + str;
190    var h = 0;
191    var off = 0;
192    for (var i = 0; i < s.length; i++) {
193        h = 31 * h + s.charCodeAt(off++);
194        h &= 0x7fffffff;
195    }
196    return h ^ s.length;
197}
198
199var tests = [
200
201    { name: 'regexp-dna.js',
202      actual: function() {
203	  return dnaOutputString + dnaInput;
204      },
205      expected: function() {
206	  return expectedDNAOutputString + expectedDNAInput;
207      },
208    },
209
210    { name: 'string-base64.js',
211      actual: function() {
212          return hash(str);
213      },
214      expected: function() {
215          return 1544571068;
216      },
217      times: rtimes,
218      rerun: function() {
219	  toBinaryTable = [
220		  -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
221		  -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
222		  -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
223	          52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
224		  -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
225	           15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
226		  -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
227	          41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
228	  ];
229	  var str = "";
230	  for (var i = 0; i < 8192; i++)
231              str += String.fromCharCode((25 * Math.random()) + 97);
232
233	  for (var i = 8192; i <= 16384; i *= 2) {
234	      var base64;
235	      base64 = toBase64(str);
236	      var encoded = base64ToString(base64);
237
238	      str += str;
239	  }
240	  toBinaryTable = null;
241      }
242    },
243    { name: 'date-format-xparb.js',
244      actual: function() {
245          return shortFormat + longFormat;
246      },
247      expected: function() {
248          return "2017-09-05Tuesday, September 05, 2017 8:43:48 AM";
249      },
250      times: rtimes,
251      rerun: function() {
252	  date = new Date("1/1/2007 1:11:11");
253	  for (i = 0; i < 4000; ++i) {
254	      var shortFormat = date.dateFormat("Y-m-d");
255	      var longFormat = date.dateFormat("l, F d, Y g:i:s A");
256	      date.setTime(date.getTime() + 84266956);
257	  }
258      }
259
260    },
261    { name: 'string-validate-input.js',
262      actual: function() {
263          return hash(endResult);
264      },
265      expected: function() {
266          return 726038055;
267      },
268      times: rtimes,
269      rerun: function() {
270	  doTest();
271      },
272    },
273    { name: '3d-morph.js',
274      actual: function() {
275          var acceptableDelta = 4e-15;
276          return (testOutput - 6.394884621840902e-14) < acceptableDelta;
277      },
278      expected: function() {
279          return true;
280      },
281      times: rtimes,
282      rerun: function() {
283	  a = Array()
284	  for (var i=0; i < nx*nz*3; ++i)
285	      a[i] = 0
286	  for (var i = 0; i < loops; ++i) {
287	      morph(a, i/loops)
288	  }
289	  testOutput = 0;
290	  for (var i = 0; i < nx; i++)
291	      testOutput += a[3*(i*nx+i)+1];
292	  a = null;
293
294      }
295    },
296    { name: 'crypto-aes.js',
297      actual: function() {
298          return plainText;
299      },
300      expected: function() {
301          return decryptedText;
302      },
303      times: rtimes,
304      rerun: function() {
305	  cipherText = AESEncryptCtr(plainText, password, 256);
306	  decryptedText = AESDecryptCtr(cipherText, password, 256);
307
308      }
309    },
310    { name: 'crypto-md5.js',
311      actual: function() {
312          return md5Output;
313      },
314      expected: function() {
315          return "a831e91e0f70eddcb70dc61c6f82f6cd";
316      },
317      times: rtimes,
318      rerun: function() {
319	  md5Output = hex_md5(plainText);
320      }
321    },
322
323    { name: 'crypto-sha1.js',
324      actual: function() {
325          return sha1Output;
326      },
327      expected: function() {
328          return "2524d264def74cce2498bf112bedf00e6c0b796d";
329      },
330      times: rtimes,
331      rerun: function() {
332	  sha1Output = hex_sha1(plainText);
333      }
334    },
335
336    { name: 'bitops-bitwise-and.js',
337      actual: function() {
338          return result;
339      },
340      expected: function() {
341          return 0;
342      },
343      times: rtimes,
344      rerun: function() {
345	  bitwiseAndValue = 4294967296;
346	  for (var i = 0; i < 600000; i++) {
347	      bitwiseAndValue = bitwiseAndValue & i;
348	  }
349	  result = bitwiseAndValue;
350      }
351    },
352
353    { name: 'bitops-bits-in-byte.js',
354      actual: function() {
355          return result;
356      },
357      expected: function() {
358          return 358400;
359      },
360      times: rtimes,
361      rerun: function() {
362	  result = TimeFunc(bitsinbyte);
363      }
364    },
365
366    { name: 'bitops-nsieve-bits.js',
367      actual: function() {
368          var ret = 0;
369          for (var i = 0; i < result.length; ++i) {
370              ret += result[i];
371          }
372          ret += result.length;
373          return ret;
374      },
375      expected: function() {
376          return -1286749539853;
377      },
378      times: rtimes,
379      rerun: function() {
380	  result = sieve();
381      }
382    },
383
384    { name: 'bitops-3bit-bits-in-byte.js',
385      actual: function() {
386          return sum;
387      },
388      expected: function() {
389          return 512000;
390      },
391      times: rtimes,
392      rerun: function() {
393	  sum = TimeFunc(fast3bitlookup);
394      }
395    },
396
397    { name: 'access-nbody.js',
398      actual: function() {
399          return ret;
400      },
401      expected: function() {
402            return -1.3524862408537381;
403      },
404      times: rtimes,
405      rerun: function() {
406	  var ret = 0;
407	  for (var n = 3; n <= 24; n *= 2) {
408	      (function(){
409		  var bodies = new NBodySystem( Array(
410		      Sun(),Jupiter(),Saturn(),Uranus(),Neptune()
411		  ));
412		  var max = n * 100;
413
414		  ret += bodies.energy();
415		  for (var i=0; i<max; i++){
416		      bodies.advance(0.01);
417		  }
418		  ret += bodies.energy();
419	      })();
420	  }
421      }
422    },
423
424    { name: 'access-binary-trees.js',
425      actual: function() {
426          return ret;
427      },
428      expected: function() {
429          return -4;
430      },
431      times: rtimes,
432      rerun: function() {
433	  ret = 0;
434
435	  for (var n = 4; n <= 7; n += 1) {
436	      var minDepth = 4;
437	      var maxDepth = Math.max(minDepth + 2, n);
438	      var stretchDepth = maxDepth + 1;
439
440	      var check = bottomUpTree(0,stretchDepth).itemCheck();
441
442	      var longLivedTree = bottomUpTree(0,maxDepth);
443	      for (var depth=minDepth; depth<=maxDepth; depth+=2){
444		  var iterations = 1 << (maxDepth - depth + minDepth);
445
446		  check = 0;
447		  for (var i=1; i<=iterations; i++){
448		      check += bottomUpTree(i,depth).itemCheck();
449		      check += bottomUpTree(-i,depth).itemCheck();
450		  }
451	      }
452
453	      ret += longLivedTree.itemCheck();
454	  }
455      }
456    },
457
458    { name: 'access-fannkuch.js',
459      actual: function() {
460          return ret;
461      },
462      expected: function() {
463          return 22;
464      },
465      times: rtimes,
466      rerun: function() {
467	  n = 8;
468	  ret = fannkuch(n);
469      }
470    },
471
472    { name: 'math-spectral-norm.js',
473      actual: function() {
474          var ret = '';
475          for (var i = 6; i <= 48; i *= 2) {
476              ret += spectralnorm(i) + ',';
477          }
478          return ret;
479      },
480      expected: function() {
481          return "1.2657786149754053,1.2727355112619148,1.273989979775574,1.274190125290389,";
482      },
483      times: rtimes,
484      rerun: function() {
485	  total = 0;
486	  for (var i = 6; i <= 48; i *= 2) {
487	      total += spectralnorm(i);
488	  }
489      }
490    },
491
492    { name: '3d-raytrace.js',
493      actual: function() {
494          return hash(testOutput);
495      },
496      expected: function() {
497          return 230692593;
498      },
499      times: rtimes,
500      rerun: function() {
501	  testOutput = arrayToCanvasCommands(raytraceScene());
502      }
503    },
504
505    { name: 'math-cordic.js',
506      actual: function() {
507          return total;
508      },
509      expected: function() {
510          return 10362.570468755888;
511      },
512      times: rtimes,
513      rerun: function() {
514	  total = 0;
515	  cordic(25000);
516      }
517    },
518
519    { name: 'controlflow-recursive.js',
520      actual: function() {
521          var ret = 0;
522          for (var i = 3; i <= 5; i++) {
523              ret += ack(3,i);
524              ret += fib(17.0+i);
525              ret += tak(3*i+3,2*i+2,i+1);
526          }
527          return ret;
528      },
529      expected: function() {
530          return 57775;
531      },
532      times: rtimes,
533      rerun: function() {
534	  result = 0;
535	  for (var i = 3; i <= 5; i++) {
536	      result += ack(3,i);
537	      result += fib(17.0+i);
538	      result += tak(3*i+3,2*i+2,i+1);
539	  }
540      }
541    },
542
543    { name: 'date-format-tofte.js',
544      actual: function() {
545          return shortFormat + longFormat;
546      },
547      expected: function() {
548          return "2008-05-01Thursday, May 01, 2008 6:31:22 PM";
549      },
550      times: rtimes,
551      rerun: function() {
552	  date = new Date("1/1/2007 1:11:11");
553	  for (i = 0; i < 500; ++i) {
554	      var shortFormat = date.formatDate("Y-m-d");
555	      var longFormat = date.formatDate("l, F d, Y g:i:s A");
556	      date.setTime(date.getTime() + 84266956);
557	  }
558      }
559    },
560
561    { name: 'string-tagcloud.js',
562      actual: function() {
563          // The result string embeds floating-point numbers, which can vary a bit on different platforms,
564          // so we truncate them a bit before comparing.
565          var tagcloud_norm = tagcloud.replace(/([0-9.]+)px/g, function(str, p1) { return p1.substr(0, 10) + 'px' })
566          return tagcloud_norm.length;
567      },
568      expected: function() {
569          return 295906;
570      },
571      times: rtimes,
572      rerun: function() {
573	  tagInfo = tagInfoJSON.parseJSON(function(a, b) { if (a == "popularity") { return Math.log(b) / log2; } else {return b; } });
574	  tagcloud = makeTagCloud(tagInfo);
575      }
576    },
577
578    { name: 'math-partial-sums.js',
579      actual: function() {
580	  return total;
581      },
582      expected: function() {
583	  return 60.08994194659945;
584      },
585      times: rtimes,
586      rerun: function() {
587	  total = 0;
588	  for (var i = 1024; i <= 16384; i *= 2) {
589	      total += partial(i);
590	  }
591      }
592    },
593
594    { name: 'access-nsieve.js',
595      actual: function() {
596	  return result;
597      },
598      expected: function() {
599	  return 14302;
600      },
601      times: rtimes,
602      rerun: function() {
603	  result = sieve();
604      }
605    },
606
607    { name: '3d-cube.js',
608      times: rtimes,
609      rerun: function() {
610	  Q = new Array();
611	  MTrans = new Array();  // transformation matrix
612	  MQube = new Array();  // position information of qube
613	  I = new Array();      // entity matrix
614	  Origin = new Object();
615	  Testing = new Object();
616	  for ( var i = 20; i <= 160; i *= 2 ) {
617	      Init(i);
618	  }
619      }
620    },
621
622    //TODO no easy way to sanity check result
623    { name: 'string-fasta.js',
624      times: rtimes,
625      rerun: function() {
626	  ret = 0;
627	  count = 7;
628	  fastaRepeat(2*count*100000, ALU);
629	  fastaRandom(3*count*1000, IUB);
630	  fastaRandom(5*count*1000, HomoSap);
631      }
632    },
633
634    //TODO no easy way to sanity check result
635    { name: 'string-unpack-code.js',
636      actual: function() {
637          return decompressedMochiKit.length == 106415 &&
638              decompressedMochiKit[2000] == '5' &&
639              decompressedMochiKit[12000] == '_' &&
640              decompressedMochiKit[82556] == '>';
641      },
642      expected: function() {
643	  return true;
644      },
645    },
646
647];
648
649tests.sort(function(a,b) { return a.name.localeCompare(b.name); });
650if (typeof single !== 'undefined') {
651    for (i in tests) {
652	if (tests[i].name === single) {
653	    singleTest = tests[i];
654	    tests = [singleTest];
655	    break;
656	}
657    }
658    if (tests.length != 1) {
659	throw "unknown single test '" + single + "'";
660    }
661}
662
663
664// handle the case this script may be run by a JS engine that doesn't
665// support __DIR__ global variable.
666
667runsuite(tests);
668
669pprint('\n' + runs + "/" + tests.length + " tests were successfully run in " + total_time + " ms ");
670
671print("Sunspider finished!");
672