Chris@3:
Chris@26: /* Utility functions to generate arbitrary input in various formats */
Chris@3:
Chris@3: function inputReals(size) {
Chris@8: var result = new Float32Array(size);
Chris@3: for (var i = 0; i < result.length; i++)
Chris@26: result[i] = (i % 2) / 4.0;
Chris@3: return result;
Chris@3: }
Chris@3:
Chris@3: function zeroReals(size) {
Chris@8: var result = new Float32Array(size);
Chris@3: for (var i = 0; i < result.length; i++)
Chris@3: result[i] = 0.0;
Chris@3: return result;
Chris@3: }
Chris@3:
Chris@37: function inputInterleaved(size) {
Chris@37: var result = new Float32Array(size*2);
Chris@37: for (var i = 0; i < size; i++)
Chris@37: result[i*2] = (i % 2) / 4.0;
Chris@37: return result;
Chris@37: }
Chris@37:
Chris@3: function inputReal64s(size) {
Chris@3: var result = new Float64Array(size);
Chris@3: for (var i = 0; i < result.length; i++)
Chris@26: result[i] = (i % 2) / 4.0;
Chris@3: return result;
Chris@3: }
Chris@3:
Chris@7: function zeroReal64s(size) {
Chris@7: var result = new Float64Array(size);
Chris@7: for (var i = 0; i < result.length; i++)
Chris@26: result[i] = 0.0;
Chris@7: return result;
Chris@7: }
Chris@7:
Chris@3: function inputComplexArray(size) {
Chris@3: var result = new complex_array.ComplexArray(size);
Chris@3: for (var i = 0; i < size; i++) {
Chris@26: result.real[i] = (i % 2) / 4.0;
Chris@3: result.imag[i] = 0.0;
Chris@3: }
Chris@3: return result;
Chris@3: }
Chris@3:
Chris@19: var iterations = 2000;
Chris@3:
Chris@3: function report(name, start, middle, end, total) {
Chris@19: function addTo(tag, thing) {
Chris@19: document.getElementById(name + "-" + tag).innerHTML += thing + "
";
Chris@19: }
Chris@19: addTo("result", total);
Chris@19: addTo("1", Math.round(middle - start) + " ms");
Chris@19: addTo("2", Math.round(end - middle) + " ms");
Chris@19: addTo("itr", Math.round((1000.0 /
Chris@19: ((end - middle) / iterations))) + " itr/sec");
Chris@3: }
Chris@3:
Chris@19: function testNayuki(size) {
Chris@3:
Chris@3: var start = performance.now();
Chris@3: var middle = start;
Chris@3: var end = start;
Chris@3:
Chris@3: var total = 0.0;
Chris@3:
Chris@3: for (var i = 0; i < 2*iterations; ++i) {
Chris@3: if (i == iterations) {
Chris@3: middle = performance.now();
Chris@3: }
Chris@3: var real = inputReals(size);
Chris@3: var imag = zeroReals(size);
Chris@3: transform(real, imag);
Chris@3: for (var j = 0; j < size; ++j) {
Chris@4: total += Math.sqrt(real[j] * real[j] + imag[j] * imag[j]);
Chris@3: }
Chris@3: }
Chris@3:
Chris@3: var end = performance.now();
Chris@3:
Chris@3: report("nayuki", start, middle, end, total);
Chris@3: }
Chris@3:
Chris@19: function testNayukiObj(size) {
Chris@17:
Chris@17: var fft = new FFTNayuki(size);
Chris@17:
Chris@17: var start = performance.now();
Chris@17: var middle = start;
Chris@17: var end = start;
Chris@17:
Chris@17: var total = 0.0;
Chris@17:
Chris@17: for (var i = 0; i < 2*iterations; ++i) {
Chris@17: if (i == iterations) {
Chris@17: middle = performance.now();
Chris@17: }
Chris@17: var real = inputReals(size);
Chris@17: var imag = zeroReals(size);
Chris@17: fft.forward(real, imag);
Chris@17: for (var j = 0; j < size; ++j) {
Chris@17: total += Math.sqrt(real[j] * real[j] + imag[j] * imag[j]);
Chris@17: }
Chris@17: }
Chris@17:
Chris@17: var end = performance.now();
Chris@17:
Chris@17: report("nayukiobj", start, middle, end, total);
Chris@17: }
Chris@17:
Chris@32: function testNayukiC(size) {
Chris@32:
Chris@32: var fft = new FFTNayukiC(size);
Chris@32:
Chris@32: var start = performance.now();
Chris@32: var middle = start;
Chris@32: var end = start;
Chris@32:
Chris@32: total = 0.0;
Chris@32:
Chris@32: for (var i = 0; i < 2*iterations; ++i) {
Chris@32: if (i == iterations) {
Chris@32: middle = performance.now();
Chris@32: }
Chris@33: var real = inputReal64s(size);
Chris@33: var imag = zeroReal64s(size);
Chris@32: fft.forward(real, imag);
Chris@32: for (var j = 0; j < size; ++j) {
Chris@32: total += Math.sqrt(real[j] * real[j] + imag[j] * imag[j]);
Chris@32: }
Chris@32: }
Chris@32:
Chris@32: var end = performance.now();
Chris@32:
Chris@32: fft.dispose();
Chris@32:
Chris@32: report("nayukic", start, middle, end, total);
Chris@32: }
Chris@32:
Chris@37: function testNayukiCF(size) {
Chris@37:
Chris@37: var fft = new FFTNayukiCFloat(size);
Chris@37:
Chris@37: var start = performance.now();
Chris@37: var middle = start;
Chris@37: var end = start;
Chris@37:
Chris@37: total = 0.0;
Chris@37:
Chris@37: for (var i = 0; i < 2*iterations; ++i) {
Chris@37: if (i == iterations) {
Chris@37: middle = performance.now();
Chris@37: }
Chris@37: var real = inputReals(size);
Chris@37: var imag = zeroReals(size);
Chris@37: fft.forward(real, imag);
Chris@37: for (var j = 0; j < size; ++j) {
Chris@37: total += Math.sqrt(real[j] * real[j] + imag[j] * imag[j]);
Chris@37: }
Chris@37: }
Chris@37:
Chris@37: var end = performance.now();
Chris@37:
Chris@37: fft.dispose();
Chris@37:
Chris@37: report("nayukicf", start, middle, end, total);
Chris@37: }
Chris@37:
Chris@19: function testNockert(size) {
Chris@3:
Chris@3: var fft = new FFT.complex(size, false);
Chris@3:
Chris@3: var start = performance.now();
Chris@3: var middle = start;
Chris@3: var end = start;
Chris@3:
Chris@3: total = 0.0;
Chris@3:
Chris@3: for (var i = 0; i < 2*iterations; ++i) {
Chris@3: if (i == iterations) {
Chris@3: middle = performance.now();
Chris@3: }
Chris@3: var ri = inputReal64s(size);
Chris@3: var co = new Float64Array(2 * size);
Chris@3: fft.simple(co, ri, 'real');
Chris@4: for (var j = 0; j < size; ++j) {
Chris@4: total += Math.sqrt(co[j*2] * co[j*2] + co[j*2+1] * co[j*2+1]);
Chris@3: }
Chris@3: }
Chris@3:
Chris@3: var end = performance.now();
Chris@3:
Chris@3: report("nockert", start, middle, end, total);
Chris@3: }
Chris@3:
Chris@19: function testDntj(size) {
Chris@3:
Chris@3: var start = performance.now();
Chris@3: var middle = start;
Chris@3: var end = start;
Chris@3:
Chris@3: total = 0.0;
Chris@4: var scale = Math.sqrt(size);
Chris@3:
Chris@3: for (var i = 0; i < 2*iterations; ++i) {
Chris@3: if (i == iterations) {
Chris@3: middle = performance.now();
Chris@3: }
Chris@3: var ci = inputComplexArray(size);
Chris@3: var co = ci.FFT();
Chris@3: for (var j = 0; j < size; ++j) {
Chris@4: total += scale *
Chris@4: Math.sqrt(co.real[j] * co.real[j] + co.imag[j] * co.imag[j]);
Chris@3: }
Chris@3: }
Chris@3:
Chris@3: var end = performance.now();
Chris@3:
Chris@4: report("dntj", start, middle, end, total);
Chris@3: }
Chris@3:
Chris@19: function testCross(size) {
Chris@7:
Chris@7: var fft = new FFTCross(size);
Chris@7:
Chris@7: var start = performance.now();
Chris@7: var middle = start;
Chris@7: var end = start;
Chris@7:
Chris@7: total = 0.0;
Chris@7:
Chris@7: for (var i = 0; i < 2*iterations; ++i) {
Chris@7: if (i == iterations) {
Chris@7: middle = performance.now();
Chris@7: }
Chris@7: var ri = inputReal64s(size);
Chris@7: var out = fft.transformReal(ri, false);
Chris@7: for (var j = 0; j < size; ++j) {
Chris@7: total +=
Chris@7: Math.sqrt(out.real[j] * out.real[j] + out.imag[j] * out.imag[j]);
Chris@7: }
Chris@7: }
Chris@7:
Chris@7: var end = performance.now();
Chris@8:
Chris@8: report("cross", start, middle, end, total);
Chris@7:
Chris@19: fft.dispose();
Chris@8: }
Chris@8:
Chris@19: function testKissFFT(size) {
Chris@8:
Chris@37: var fft = new KissFFTR(size);
Chris@8:
Chris@8: var start = performance.now();
Chris@8: var middle = start;
Chris@8: var end = start;
Chris@8:
Chris@8: total = 0.0;
Chris@8:
Chris@8: for (var i = 0; i < 2*iterations; ++i) {
Chris@8: if (i == iterations) {
Chris@8: middle = performance.now();
Chris@8: }
Chris@8: var ri = inputReals(size);
Chris@8: var out = fft.forward(ri);
Chris@8: for (var j = 0; j <= size/2; ++j) {
Chris@8: total += Math.sqrt(out[j*2] * out[j*2] + out[j*2+1] * out[j*2+1]);
Chris@8: }
Chris@37: // KissFFTR returns only the first half of the output (plus
Chris@8: // DC/Nyquist) -- synthesise the conjugate half
Chris@8: for (var j = 1; j < size/2; ++j) {
Chris@8: total += Math.sqrt(out[j*2] * out[j*2] + out[j*2+1] * out[j*2+1]);
Chris@8: }
Chris@8: }
Chris@8:
Chris@8: var end = performance.now();
Chris@8:
Chris@8: report("kissfft", start, middle, end, total);
Chris@8:
Chris@19: fft.dispose();
Chris@7: }
Chris@7:
Chris@37: function testKissFFTCC(size) {
Chris@37:
Chris@37: var fft = new KissFFT(size);
Chris@37:
Chris@37: var start = performance.now();
Chris@37: var middle = start;
Chris@37: var end = start;
Chris@37:
Chris@37: total = 0.0;
Chris@37:
Chris@37: for (var i = 0; i < 2*iterations; ++i) {
Chris@37: if (i == iterations) {
Chris@37: middle = performance.now();
Chris@37: }
Chris@37: var cin = inputInterleaved(size);
Chris@37: var out = fft.forward(cin);
Chris@37: for (var j = 0; j < size; ++j) {
Chris@37: total += Math.sqrt(out[j*2] * out[j*2] + out[j*2+1] * out[j*2+1]);
Chris@37: }
Chris@37: }
Chris@37:
Chris@37: var end = performance.now();
Chris@37:
Chris@37: report("kissfftcc", start, middle, end, total);
Chris@37:
Chris@37: fft.dispose();
Chris@37: }
Chris@37:
Chris@19: function testFFTW(size) {
Chris@19:
Chris@19: var fft = new FFTW(size);
Chris@19:
Chris@19: var start = performance.now();
Chris@19: var middle = start;
Chris@19: var end = start;
Chris@19:
Chris@19: total = 0.0;
Chris@19:
Chris@19: for (var i = 0; i < 2*iterations; ++i) {
Chris@19: if (i == iterations) {
Chris@19: middle = performance.now();
Chris@19: }
Chris@19: var ri = inputReals(size);
Chris@19: var out = fft.forward(ri);
Chris@19: for (var j = 0; j <= size/2; ++j) {
Chris@19: total += Math.sqrt(out[j*2] * out[j*2] + out[j*2+1] * out[j*2+1]);
Chris@19: }
Chris@19: // FFTW returns only the first half of the output (plus
Chris@19: // DC/Nyquist) -- synthesise the conjugate half
Chris@19: for (var j = 1; j < size/2; ++j) {
Chris@19: total += Math.sqrt(out[j*2] * out[j*2] + out[j*2+1] * out[j*2+1]);
Chris@19: }
Chris@19: }
Chris@19:
Chris@19: var end = performance.now();
Chris@19:
Chris@19: report("fftw", start, middle, end, total);
Chris@19:
Chris@19: fft.dispose();
Chris@19: }
Chris@19:
Chris@40: var sizes = [ 4, 8, 512, 2048 ];
Chris@37: var tests = [ testNayuki, testNayukiObj, testNayukiC, testNayukiCF,
Chris@37: testKissFFT, testKissFFTCC, testCross, testFFTW,
Chris@37: testNockert, testDntj ];
Chris@16: var nextTest = 0;
Chris@19: var nextSize = 0;
Chris@16: var interval;
Chris@16:
Chris@3: function test() {
Chris@16: clearInterval(interval);
Chris@19: if (nextTest == tests.length) {
Chris@19: nextSize++;
Chris@19: nextTest = 0;
Chris@19: if (nextSize == sizes.length) {
Chris@19: return;
Chris@19: }
Chris@16: }
Chris@19: f = tests[nextTest];
Chris@19: size = sizes[nextSize];
Chris@19: nextTest++;
Chris@19: f(size);
Chris@19: interval = setInterval(test, 100);
Chris@16: }
Chris@3:
Chris@16: window.onload = function() {
Chris@3: document.getElementById("test-description").innerHTML =
Chris@19: "Running " + 2*iterations + " iterations per implementation.
Timings are given separately for the first half of the run (" + iterations + " iterations) and the second half, in case the JS engine takes some warming up.
Each cell contains results for the following sizes: " + sizes;
Chris@19: interval = setInterval(test, 100);
Chris@3: }
Chris@3: