あいつの日誌β

働きながら旅しています。

Test-Driven JavaScript Development に記述されているベンチマークコードを試す

年始のあいさつ

明けましておめでとうございます。本年も宜しくお願いします。

コードの出所

% git clone http://tddjs.com/code/04-test-to-learn.git

雛形作成

% mkdir Practice-JsBench/
% cd Practice-JsBench

HTML作成

% mkdir root
% vi root/benchmark.html
<!DOCTYPE html>
<html>
<head>
  <title>Benchmark test</title>
</head>
<body>
    <script src="/js/mylibs/mybench.js"></script>
    <script src="/js/mylibs/benchmark_loops.js"></script>
</body>
</html>

ベンチ用関数を用意

% mkdir -p root/js/mylibs/
% vi root/js/mylibs/mybench.js
var benchmark = (function () {
    var times = {};

	function init(name) {
		var heading = document.createElement("h2");
		heading.innerHTML = name;
		document.body.appendChild(heading);

		var ol = document.createElement("ol");
		document.body.appendChild(ol);

		return ol;
	}

	function runTests(tests, view, iterations) {
		
        for (var label in tests) {
			
            if (!tests.hasOwnProperty(label) || typeof tests[label] != "function") {
				continue;
			}

            (function (name, test) {
                setTimeout(function () {
                    var start = new Date().getTime();
                    var l = iterations;

                    while (l--) {
                        test();
                    }

                    var total = new Date().getTime() - start;
                    times[name] = total;

                    var li = document.createElement("li");
                    li.innerHTML = name + ": " + total +
                    "ms (total), " + (total / iterations) +
                    "ms (avg)";
                    view.appendChild(li);
                }, 15);
            }(label, tests[label]));
		}
        
	}
   
    function highlightExtremes(view) {
        // タイムアウトはほかのすべてのタイマーのあとにキューイングされる
        // すべてのテストが実行を週虜うし、
        // timesオブジェクトに値がセットされているが保証される
        setTimeout(function () {
            var min = new Date().getTime();
            var max = 0;
            var fastest, slowest;

            for (var label in times) {
                if (!times.hasOwnProperty(label)) {
                    continue;
                }
                
                if (times[label] < min) {
                    min = times[label];
                    fastest = label;
                }

                if (times[label] > max) {
                    max = times[label];
                    slowest = label;
                }
            }

            var lis = view.getElementsByTagName("li");
            var fastRegexp = new RegExp("^" + fastest + ":");
            var slowRegexp = new RegExp("^" + slowest + ":");

            for (var i = 0, l = lis.length; i < l; i++) {
                if (slowRegexp.test(lis[i].innerHTML)) {
                    lis[i].style.color = "#c00";
                }

                if (fastRegexp.test(lis[i].innerHTML)) {
                    lis[i].style.color = "#0c0";
                }
            }
        }, 15);
    }

    function benchmark(name, tests, iterations) {
        iterations = iterations || 1000;
        var view = init(name);
        runTests(tests, view, iterations);
        highlightExtremes(view);
    }

    return benchmark;
}());

計測対象となるスクリプトを用意

% vi root/js/mylibs/benchmark_loop.js
var loopLength = 100000;

// ループ実行のために配列をセット
var array = [];

for (var i = 0; i < loopLength; i++) {
	array[i] = "item" + i;
}

benchmark("Loop performance", {
    "for-loop": function () {
	    for (var i = 0, item; i < array.length; i++) {
		    item = array[i];
	    }
    },

    "for-loop, cached length": function () {
	    for (var i = 0, l = array.length, item; i < l; i++) {
		    item = array[i];
	    }
    }
}, 1000);

pspiを用意

% vi static.psgi
use Plack::Builder;
builder {
enable "Plack::Middleware::Static",
    path => sub { s!(.*/$)!${1}/index.html!  },
    root => './root/';
};

実行

% plackup static.psgi

感想

Test-Driven JavaScript Development 翻訳されてます。