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