Subversion Repositories Applications.papyrus

Rev

Blame | Last modification | View Log | RSS feed

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <title>Builder Perf Tests</title>
    <script type="text/javascript" src="../../../dojo/dojo.js"></script>
    <script type="text/javascript" src="../Builder.js"></script>
    <script type="text/javascript" src="lipsum.js"></script>
    <script type="text/javascript">

    dojo.addOnLoad(function(){
      dojo.byId("run").disabled="";
      dojo.connect(dojo.byId("run"), 
                   "onclick", 
                   function(evt) { 
                     setTimeout(function() { 
                       var words = parseInt(dojo.byId("numWords").value) || 10;
                       var iters = parseInt(dojo.byId("numIters").value) || 1000;
                       var dict = eval(dojo.byId("dict").value);
                       buildAndRunSet(words, dict, iters); 
                      }, 0); 
                    });
    });
    
    function element(tag, textOrChildOrArray) {
      var e = document.createElement(tag);
      function append(n) {
        if(dojo.isString(n)){
          n = document.createTextNode(n);
        } 
        e.appendChild(n);
      }
      if(dojo.isArray(textOrChildOrArray)) {
        dojo.forEach(textOrChildOrArray, append);
      }else{
        append(textOrChildOrArray);
      }
      return e;
    }
    
    function log(t) {
      dojo.byId("mess").innerHTML = t;
      console.log(t);
    }
    
    function reportRun(results){
      var runs = results.runs
      var report = element("dl",
                     element("dt", 
                             "Run with " + results.words + " words, " + 
                                           results.iterations + " iterations, for loop overhead of " + 
                                           results.overhead + ", average phrase of " +
                                           results.wordSize + " characters"));
                          
      runs.sort(function(a,b) { return a.time - b.time; });
      dojo.forEach(runs, function(r) {
        report.appendChild(element("dd", r.time + " - " + r.name));
      });
      
      dojo.body().appendChild(report);
    }
    
    function runTest(test, iterations, expected) {
      var i;
      if(expected != test()) throw new Error("Test failed expecting " + expected + ", got " + test());
      var start = new Date().getTime(), end;
      for(i=0; i < iterations; i++){
        test();
      }
      end = new Date().getTime();
      return end-start;
    }
    
    function runSet(set, iterations){
      
      function averagePhraseLen(words) {
        var sizes = dojo.map(words, function(w) { return w.length; });
        var total = 0;
        dojo.forEach(sizes, function(s) { total += s; });
        return total / sizes.length;
      }
      
      var tests = set.tests.concat(); //copy tests
      var resultSet = {};
      resultSet.words = set.words.length;
      resultSet.overhead = runTest(set.overhead, iterations);
      resultSet.iterations = iterations;
      resultSet.wordSize = averagePhraseLen(set.words);
      var runs = [];
      
      function _run() {
        var t = tests.pop();
        try {
          log("Running " + t.name);
          if(t) runs.push({ name: t.name, time: runTest(t.test, iterations, set.expected)});
        } catch(e) {
          console.error("Error running " + t.name);
          console.error(e);
        }
        if(tests.length > 0) {
          setTimeout(_run, 0);
        }
        else {
          log("Done!");
          resultSet.runs = runs;
          reportRun(resultSet);
          dojo.publish("perf/run/done");
        }
      }
      setTimeout(_run, 25);
    }
    
    function buildTestSet(numWords, dict) {
      var words = [], i, dl = dict.length;
      for(i = numWords; i > 0; i-=dl) { 
        if(i >= dl) { words = words.concat(dict); }
        else { words = words.concat(dict.slice(-i)); } 
      }
      if(words.length != numWords) throw new Error("wrong number of words, got " + words.length + ", expected " + numWords);
      
      var expected = words.join("");
      
      var _builder = new dojox.string.Builder();
      
      return { 
        tests: [
          {
            name: "concatFor",
            test: function() {
              var s = "";
              for(var i = 0; i < words.length; i++) {
                s = s.concat(words[i]);
              }
              return s;
            }
          },
          /*
          {
            name: "concatForAlias",
            test: function() {
              var s = "", w = words, l = w.length;
              for(var i = 0; i < l; i++) {
                s = s.concat(w[i]);
              }
              return s;
            }
          },
          {
            name: "concatForEach",
            test: function() {
              var s = "";
              dojo.forEach(words, function(w) {
                s = s.concat(w);
              });
              return s;
            }
          },
          */
          {
            name: "concatOnce",
            test: function() {
              var s = "";
              s = String.prototype.concat.apply(s, words);
              return s;
            }
          },
          {
            name: "builderFor",
            test: function() {
              var b = new dojox.string.Builder();
              for(var i = 0; i < words.length; i++) {
                b.append(words[i]);
              }
              return b.toString();
            }
          },
          /*
          {
            name: "builderForEach",
            test: function() {
              var b = new dojox.string.Builder();
              dojo.forEach(words, function(w) {
                b.append(w);
              });
              return b.toString();
            }
          },
          */
          {
            name: "builderReusedFor",
            test: function() {
              _builder.clear();
              for(var i = 0; i < words.length; i++) {
                _builder.append(words[i]);
              }
              return _builder.toString();
            }
          },
          {
            name: "builderOnce",
            test: function() {
              var b = new dojox.string.Builder();
              b.appendArray(words);
              return b.toString();
            }
          },
          {
            name: "builderReusedOnce",
            test: function() {
              _builder.clear();
              _builder.appendArray(words);
              return _builder.toString();
            }
          },
          {
            name: "plusFor",
            test: function() {
              var s = "";
              for(var i = 0; i < words.length; i++) {
                s += words[i];
              }
              return s;
            }
          },
          /*
          {
            name: "plusForAlias",
            test: function() {
              var s = "", w = words, l = w.length;
              for(var i = 0; i < l; i++) {
                s += w[i];
              }
              return s;
            }
          },
          {
            name: "plusForEach",
            test: function() {
              var s = "";
              dojo.forEach(words, function(w) { s += w; });
              return s;
            }
          },*/
          {
            name: "joinOnce",
            test: function() {
              return words.join("");
            }
          },
          {
            name: "joinFor",
            test: function() {
              var a = [];
              for(var i = 0; i < words.length; i++) {
                a.push(words[i]);
              }
              return a.join("");
            }
          }/*,
          {
            name: "joinForAlias",
            test: function() {
              var a = [], w = words, l = w.length;
              for(var i = 0; i <l; i++) {
                a.push(w[i]);
              }
              return a.join("");
            }
          },
          {
            name: "joinForEach",
            test: function() {
              var a = [];
              dojo.forEach(words, function(w) { a.push(w); });
              return a.join("");
            }
          }
          */
        ],
        words: words,
        expected: expected,
        overhead: function() { 
          var w = words; 
          var l = w.length; 
          for(var i=0; i < l; i++) { 
            ident(w[i]); 
          } 
        }
      };
    }
    
    function buildAndRunSet(words, dict, times) {
      runSet(buildTestSet(words, dict), times);
    }
    
    function runSuite() {
      var suite = [
        {
          words: 2,
          times: 10000
        },
        {
          words: 4,
          times: 10000
        },
        {
          words: 8,
          times: 10000
        },
        {
          words: 16,
          times: 10000
        },
        {
          words: 32,
          times: 10000
        },
        {
          words: 64,
          times: 10000
        },
        {
          words: 128,
          times: 1000
        },
        {
          words: 256,
          times: 1000
        },
        {
          words: 512,
          times: 1000
        },
        {
          words: 1024,
          times: 1000
        },
        {
          words: 2048,
          times: 1000
        },
        {
          words: 4096,
          times: 100
        },
        {
          words: 8192,
          times: 100
        }
      ];
      
      var totalSuite = dojo.map(suite, function(s) { var n = {}; dojo.mixin(n,s); n.dict = lipsum; return n; });
      totalSuite = totalSuite.concat(dojo.map(suite, function(s) { var n = {}; dojo.mixin(n,s); n.dict = lipsumLong; return n; }));
      console.log(totalSuite);
      
      var handle = dojo.subscribe("perf/run/done", _run);
      dojo.subscribe("perf/run/done", function(){ console.log("perf run done"); });
      
      function _run() {
        var t = totalSuite.shift();
        if(t) buildAndRunSet(t.words, t.dict, t.times);
        if(totalSuite.length == 0) dojo.unsubscribe(handle);
      }
      
      _run();
    }
    
    function ident(i) { return i; }
    </script>
    <style type="text/css">
    html { 
      font-family: Lucida Grande, Tahoma;
    }
    div { margin-bottom: 1em; }
    #results {
      border: 1px solid #999;
      border-collapse: collapse;
    }
    #results caption {
      font-size: medium;
      font-weight: bold;
    }
    #results td, #results th {
      text-align: right;
      width: 10em;
      font-size: small;
      white-space: nowrap;
    }
    #wordsCol { background: yellow; }
    td.max { color: red; font-weight: bold; }
    td.min { color: green; font-weight: bold; }
    </style>
  </head>
  <body>
    <table>
      <tr><td><label for="numWords">Words</label></td><td><input type="text" id="numWords" value="100"/></td></tr>
      <tr><td><label for="numIters">Iterations</label></td><td><input type="text" id="numIters" value="1000"/></td></tr>
      <tr><td><label for="dict">Dictionary</label></td><td><input type="text" id="dict" value="lipsum"></td></tr>
      <tr><td></td><td><button id="run" disabled>Run Tests!</button></td></tr>
    </table>
    <div id="mess"></div>    
  </body>
</html>