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