benchmark.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. var fs = require('fs');
  2. var PNG = require('png-js');
  3. var BENCHMARK_FILENAME = 'benchmark.json';
  4. var PATH_PERF_TESTS = 'test/perf';
  5. var PATH_BENCHMARK_FILE = 'test/assets/' + BENCHMARK_FILENAME;
  6. var TEST_TIMES_RUN = 5;
  7. var TIME_THRESHOLD = 30;
  8. var Benchmark = {
  9. /**
  10. * Calls the setUp function for all performance tests.
  11. * @param {function} done Function to be called when the set up is done.
  12. */
  13. setUpAll: function(done) {
  14. readTestFiles(function(files) {
  15. Benchmark.files = files;
  16. runAllSetUps(done);
  17. });
  18. },
  19. /**
  20. * Runs all the performance tests.
  21. * @param {function} callback Function to be called when all tests finish running.
  22. */
  23. runAll: function(callback) {
  24. var results;
  25. getBenchmarkContents(function(benchmark) {
  26. results = runAllTests(benchmark);
  27. fs.writeFile(PATH_BENCHMARK_FILE, JSON.stringify(benchmark), function() {
  28. callback(results);
  29. });
  30. });
  31. },
  32. /**
  33. * Creates a failure message for the given results.
  34. * @param {array} results An array with the results of the performance tests.
  35. */
  36. createFailureMessage: function(results) {
  37. var message = '';
  38. for(var i = 0; i < results.length; i++) {
  39. if (results[i].failedTests.length > 0) {
  40. message += '\n' + results[i].failedTests.length + ' failures for ' + results[i].filename + ':';
  41. for (var j = 0; j < results[i].failedTests.length; j++) {
  42. message += '\n\t' + results[i].failedTests[j];
  43. }
  44. }
  45. }
  46. return message;
  47. }
  48. };
  49. /**
  50. * Gets the contents of the benchmark json file.
  51. * @param {function} callback Function to be called with the contents.
  52. */
  53. function getBenchmarkContents(callback){
  54. fs.exists(PATH_BENCHMARK_FILE, function (exists) {
  55. if (exists) {
  56. fs.readFile(PATH_BENCHMARK_FILE, 'utf8', function(error, data) {
  57. callback(JSON.parse(data));
  58. });
  59. } else {
  60. callback({});
  61. }
  62. });
  63. }
  64. /**
  65. * Reads all performance test files.
  66. * @param {function} callback Function to be called when all tests are read.
  67. */
  68. function readTestFiles(callback) {
  69. fs.readdir(PATH_PERF_TESTS, function(error, files_list) {
  70. var files = [];
  71. for (var i = 0; i < files_list.length; i++) {
  72. var filename = files_list[i];
  73. if (filename.match('.*.js$')) {
  74. files.push({
  75. filename: filename,
  76. test: require('../../' + PATH_PERF_TESTS + '/' + filename)
  77. });
  78. }
  79. }
  80. callback(files);
  81. });
  82. }
  83. /**
  84. * Runs the setUp function for each performance test.
  85. * @param {function} callback Function to be called when all set ups are done.
  86. */
  87. function runAllSetUps(callback) {
  88. Benchmark.totalDone = 0;
  89. for (var i = 0; i < Benchmark.files.length; i++) {
  90. test = Benchmark.files[i].test;
  91. if (test.setUp) {
  92. test.setUp(function() {
  93. setUpDone(callback);
  94. });
  95. } else {
  96. setUpDone(callback);
  97. }
  98. }
  99. }
  100. /**
  101. * Runs all the performance tests.
  102. * @param {object} benchmark Information about duration of previous test runs.
  103. */
  104. function runAllTests(benchmark) {
  105. var allResults = [];
  106. var benchmarkTime;
  107. var benchmarkTimes;
  108. var currentResults;
  109. var duration;
  110. var filename;
  111. var passed = true;
  112. var test;
  113. for (var i = 0; i < Benchmark.files.length; i++) {
  114. filename = Benchmark.files[i].filename;
  115. test = Benchmark.files[i].test;
  116. if (!benchmark[filename]) {
  117. benchmark[filename] = {};
  118. }
  119. currentResults = {
  120. filename: filename,
  121. failedTests: [],
  122. passedTests: []
  123. };
  124. for (var key in test) {
  125. if (test.hasOwnProperty(key) && (typeof test[key] === 'function') && key !== 'setUp') {
  126. duration = runTest(test[key]);
  127. benchmarkTimes = benchmark[filename][key];
  128. if (benchmarkTimes && benchmarkTimes.length) {
  129. benchmarkTime = benchmarkTimes[benchmarkTimes.length - 1];
  130. if (duration > benchmarkTime + TIME_THRESHOLD) {
  131. currentResults.failedTests.push(key);
  132. passed = false;
  133. }
  134. else {
  135. currentResults.passedTests.push(key);
  136. benchmark[filename][key].push(duration);
  137. }
  138. }
  139. else {
  140. currentResults.passedTests.push(key);
  141. benchmark[filename][key] = [duration];
  142. }
  143. }
  144. }
  145. allResults.push(currentResults);
  146. }
  147. return {
  148. passed: passed,
  149. resultDetails: allResults
  150. };
  151. }
  152. /**
  153. * Runs a single test.
  154. * @param {object} test The test to be run.
  155. */
  156. function runTest(test) {
  157. var timeBefore;
  158. var timeTotal = 0;
  159. for (var i = 0; i < TEST_TIMES_RUN; i++) {
  160. timeBefore = new Date().getTime();
  161. test();
  162. timeTotal += new Date().getTime() - timeBefore;
  163. }
  164. return timeTotal / TEST_TIMES_RUN;
  165. }
  166. /**
  167. * Increments the number of setUp functions that are done, and invokes the callback when all
  168. * have been finished.
  169. * @param {function} callback The function to be called when the last setUp function is done
  170. */
  171. function setUpDone(callback) {
  172. Benchmark.totalDone++;
  173. if (Benchmark.totalDone === Benchmark.files.length) {
  174. callback();
  175. }
  176. }
  177. module.exports = Benchmark;