mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 872352 - Add liquid-resize and other benchmarks into parjs-benchmarks rs=tests
This commit is contained in:
parent
5121b27fe0
commit
d0cda62dd5
152
js/src/parjs-benchmarks/edges.js
Normal file
152
js/src/parjs-benchmarks/edges.js
Normal file
@ -0,0 +1,152 @@
|
||||
load(libdir + "util.js");
|
||||
|
||||
function stripedImage(w, h) {
|
||||
var resultArray = new Array(w * h);
|
||||
for (var x = 0; x < w; x++) {
|
||||
for (var y = 0; y < h; y++) {
|
||||
resultArray[x*h + y] = (Math.abs(x%100-y%100) < 10) ? 32 : 0;
|
||||
}
|
||||
}
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
function edges1dArraySequentially(data, width, height) {
|
||||
var sobelX = [[-1.0, 0.0, 1.0],
|
||||
[-2.0, 0.0, 2.0],
|
||||
[-1.0, 0.0, 1.0]];
|
||||
var sobelY = [[1.0, 2.0, 1.0],
|
||||
[0.0, 0.0, 0.0],
|
||||
[-1.0, -2.0, -1.0]];
|
||||
|
||||
var data1 = new Array(width * height);
|
||||
for (var y = 0; y < height; y++) {
|
||||
for (var x = 0; x < width; x++) {
|
||||
// process pixel
|
||||
var totalX = 0;
|
||||
var totalY = 0;
|
||||
for (var offY = -1; offY <= 1; offY++) {
|
||||
var newY = y + offY;
|
||||
for (var offX = -1; offX <= 1; offX++) {
|
||||
var newX = x + offX;
|
||||
if ((newX >= 0) && (newX < width) && (newY >= 0) && (newY < height)) {
|
||||
var pointIndex = (x + offX) * height + (y + offY);
|
||||
var e = data[pointIndex];
|
||||
totalX += e * sobelX[offY + 1][offX + 1];
|
||||
totalY += e * sobelY[offY + 1][offX + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
var total = ((Math.abs(totalX) + Math.abs(totalY))/8.0)|0;
|
||||
var index = y*width+x;
|
||||
data1[index] = total | 0;
|
||||
}
|
||||
}
|
||||
return data1;
|
||||
}
|
||||
|
||||
/* Compute edges using a flat JS array as input */
|
||||
function edges1dArrayInParallel(data, width, height) {
|
||||
var sobelX = [[-1.0, 0.0, 1.0],
|
||||
[-2.0, 0.0, 2.0],
|
||||
[-1.0, 0.0, 1.0]];
|
||||
var sobelY = [[1.0, 2.0, 1.0],
|
||||
[0.0, 0.0, 0.0],
|
||||
[-1.0, -2.0, -1.0]];
|
||||
|
||||
function computePixel(x, y) {
|
||||
var totalX = 0;
|
||||
var totalY = 0;
|
||||
for (var offY = -1; offY <= 1; offY++) {
|
||||
var newY = y + offY;
|
||||
for (var offX = -1; offX <= 1; offX++) {
|
||||
var newX = x + offX;
|
||||
if ((newX >= 0) && (newX < width) && (newY >= 0) && (newY < height)) {
|
||||
var pointIndex = (x + offX) * height + (y + offY);
|
||||
var e = data[pointIndex];
|
||||
totalX += e * sobelX[offY + 1][offX + 1];
|
||||
totalY += e * sobelY[offY + 1][offX + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
var total = (Math.abs(totalX) + Math.abs(totalY))/8.0 | 0;
|
||||
return total;
|
||||
}
|
||||
|
||||
return new ParallelArray([width, height], computePixel);
|
||||
}
|
||||
|
||||
/* Compute edges using a flat JS array as input */
|
||||
function edges1dParallelArrayInParallel(pa, width, height) {
|
||||
var sobelX = [[-1.0, 0.0, 1.0],
|
||||
[-2.0, 0.0, 2.0],
|
||||
[-1.0, 0.0, 1.0]];
|
||||
var sobelY = [[1.0, 2.0, 1.0],
|
||||
[0.0, 0.0, 0.0],
|
||||
[-1.0, -2.0, -1.0]];
|
||||
|
||||
function computePixel(x, y) {
|
||||
var totalX = 0;
|
||||
var totalY = 0;
|
||||
for (var offY = -1; offY <= 1; offY++) {
|
||||
var newY = y + offY;
|
||||
for (var offX = -1; offX <= 1; offX++) {
|
||||
var newX = x + offX;
|
||||
if ((newX >= 0) && (newX < width) && (newY >= 0) && (newY < height)) {
|
||||
var pointIndex = (x + offX) * height + (y + offY);
|
||||
// var e = pa.buffer[pointIndex];
|
||||
var e = pa.get(pointIndex);
|
||||
totalX += e * sobelX[offY + 1][offX + 1];
|
||||
totalY += e * sobelY[offY + 1][offX + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
var total = (Math.abs(totalX) + Math.abs(totalY))/8.0 | 0;
|
||||
return total;
|
||||
}
|
||||
|
||||
return new ParallelArray([width, height], computePixel);
|
||||
}
|
||||
|
||||
/* Compute edges using 2D parallel array as input */
|
||||
function edges2dParallelArrayInParallel(pa) {
|
||||
var sobelX = [[-1.0, 0.0, 1.0],
|
||||
[-2.0, 0.0, 2.0],
|
||||
[-1.0, 0.0, 1.0]];
|
||||
var sobelY = [[1.0, 2.0, 1.0],
|
||||
[0.0, 0.0, 0.0],
|
||||
[-1.0, -2.0, -1.0]];
|
||||
|
||||
var width = pa.shape[0];
|
||||
var height = pa.shape[1];
|
||||
|
||||
function computePixel(x, y) {
|
||||
var totalX = 0;
|
||||
var totalY = 0;
|
||||
for (var offY = -1; offY <= 1; offY++) {
|
||||
var newY = y + offY;
|
||||
for (var offX = -1; offX <= 1; offX++) {
|
||||
var newX = x + offX;
|
||||
if ((newX >= 0) && (newX < width) && (newY >= 0) && (newY < height)) {
|
||||
var pointIndex = (x + offX) * height + (y + offY);
|
||||
// var e = pa.buffer[pointIndex];
|
||||
var e = pa.get(x + offX, y + offY);
|
||||
totalX += e * sobelX[offY + 1][offX + 1];
|
||||
totalY += e * sobelY[offY + 1][offX + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
var total = (Math.abs(totalX) + Math.abs(totalY))/8.0 | 0;
|
||||
return total;
|
||||
}
|
||||
|
||||
return new ParallelArray([width, height], computePixel);
|
||||
}
|
||||
|
||||
var Width = 1024;
|
||||
var Height = 768;
|
||||
var ArrInput = stripedImage(1024, 768);
|
||||
var ParArrInput1D = new ParallelArray(ArrInput);
|
||||
var ParArrInput2D = new ParallelArray([1024, 768],
|
||||
function (x, y) ArrInput[x*Height + y]);
|
||||
|
||||
|
6
js/src/parjs-benchmarks/edgesArray1D.js
Normal file
6
js/src/parjs-benchmarks/edgesArray1D.js
Normal file
@ -0,0 +1,6 @@
|
||||
load(libdir + "edges.js");
|
||||
|
||||
benchmark("EDGES-ARRAY-1D", 1, DEFAULT_MEASURE,
|
||||
function() {edges1dArraySequentially(ArrInput, Width, Height)},
|
||||
function() {edges1dArrayInParallel(ArrInput, Width, Height)});
|
||||
|
6
js/src/parjs-benchmarks/edgesParallelArray1D.js
Normal file
6
js/src/parjs-benchmarks/edgesParallelArray1D.js
Normal file
@ -0,0 +1,6 @@
|
||||
load(libdir + "edges.js");
|
||||
|
||||
benchmark("EDGES-PARALLEL-ARRAY-1D", 1, DEFAULT_MEASURE,
|
||||
function() {edges1dArraySequentially(ArrInput, Width, Height)},
|
||||
function() {edges1dParallelArrayInParallel(ParArrInput1D, Width, Height)});
|
||||
|
5
js/src/parjs-benchmarks/edgesParallelArray2D.js
Normal file
5
js/src/parjs-benchmarks/edgesParallelArray2D.js
Normal file
@ -0,0 +1,5 @@
|
||||
load(libdir + "edges.js");
|
||||
|
||||
benchmark("EDGES-PARALLEL-ARRAY-2D", 1, DEFAULT_MEASURE,
|
||||
function() {edges1dArraySequentially(ArrInput, Width, Height)},
|
||||
function() {edges2dParallelArrayInParallel(ParArrInput2D)});
|
751
js/src/parjs-benchmarks/liquid-resize.js
Normal file
751
js/src/parjs-benchmarks/liquid-resize.js
Normal file
@ -0,0 +1,751 @@
|
||||
// -*- mode: js2; indent-tabs-mode: nil; -*-
|
||||
|
||||
// Adapted from
|
||||
//
|
||||
// https://github.com/RiverTrail/RiverTrail/blob/master/examples/liquid-resize/resize-compute-dp.js
|
||||
//
|
||||
// which in turn is based on an algorithm from the paper below (which
|
||||
// also appeared in ACM SIGGRAPH 2007):
|
||||
// Shai Avidan and Ariel Shamir. 2007. Seam carving for content-aware image resizing.
|
||||
// ACM Trans. Graph. 26, 3, Article 10 (July 2007).
|
||||
// DOI=10.1145/1276377.1276390 http://doi.acm.org/10.1145/1276377.1276390
|
||||
|
||||
// Assumption: if MODE defined then running under benchmark script
|
||||
var benchmarking = (typeof(MODE) != "undefined");
|
||||
|
||||
// Assumption: if libdir undefined then it is current directory (but this one we warn about)
|
||||
if (typeof(libdir) == "undefined") {
|
||||
print("Selecting default libdir of './';");
|
||||
print("you should override if you are not running from current directory.");
|
||||
var libdir = "./";
|
||||
}
|
||||
|
||||
if (benchmarking) {
|
||||
// util.js provides interface for benchmark infrastructure.
|
||||
load(libdir + "util.js");
|
||||
}
|
||||
|
||||
// rectarray.js provides 2D array abstraction for interactive development in REPL.
|
||||
load(libdir + "rectarray.js");
|
||||
|
||||
// A RectArray is a 2D array class exported by rectarray.js.
|
||||
// It has width and height properties, and a get(i,j) method.
|
||||
//
|
||||
// A RectArray of Nat is thought of as an image, where the natural
|
||||
// number contents are the "colors" at that point in the image.
|
||||
//
|
||||
// A WrapArray is a drop-in replacement for a RectArray.
|
||||
// (It uses a different representation.)
|
||||
|
||||
// A ParallelArray is assumed to be 2D throughout this code.
|
||||
|
||||
// A ParMode is an object with properties mode [, expect]; see ParallelArray.js
|
||||
|
||||
// A Path is an Array of indices, related to an origin RectArray R.
|
||||
// Horizontal paths are of length R.width and have elements in [0,R.height-1];
|
||||
// vertical paths are of length R.height and have elements in [0,R.width-1].
|
||||
|
||||
// A PhaseTimes is an object with various properties naming phases of a
|
||||
// computation; each property maps to a number.
|
||||
|
||||
// Ideally, one needs only change the below constructions
|
||||
// to build4 to approximate "real image" input.
|
||||
// (However, this is untested.)
|
||||
|
||||
// To see the images, try e.g. smallImage.print()
|
||||
|
||||
var tinyImage =
|
||||
WrapArray.build(20, 5,
|
||||
function(x, y, k) {
|
||||
var ret;
|
||||
if (6 <= x && x < 8 && 0 <= y && y < 4)
|
||||
ret = ".";
|
||||
else if ((x-15)*(x-15)+(y-1)*(y-1) < 2)
|
||||
ret = "^";
|
||||
else if ((x-20)*(x-20)+(y-3)*(y-3) < 2)
|
||||
ret = "%";
|
||||
else if ((x-1)*(x-1)+(y-3)*(y-3) < 2)
|
||||
ret = "@";
|
||||
else
|
||||
ret = " ";
|
||||
return ret.charCodeAt(0) - 32;
|
||||
});
|
||||
|
||||
var smallImage =
|
||||
WrapArray.build(60, 15,
|
||||
function(x, y, k) {
|
||||
var ret;
|
||||
if (6 <= x && x < 8 && 0 <= y && y < 7)
|
||||
ret = ".";
|
||||
else if ((x-15)*(x-15)+(y-1)*(y-1) < 2)
|
||||
ret = "^";
|
||||
else if ((x-40)*(x-40)+(y-6)*(y-6) < 6)
|
||||
ret = "%";
|
||||
else if ((x-1)*(x-1)+(y-12)*(y-12) < 2)
|
||||
ret = "@";
|
||||
else
|
||||
ret = " ";
|
||||
return ret.charCodeAt(0) - 32;
|
||||
});
|
||||
|
||||
var bigImage =
|
||||
WrapArray.build(200, 70,
|
||||
function(x, y, k) {
|
||||
var ret;
|
||||
if (4 <= x && x < 7 && 10 <= y && y < 40)
|
||||
ret = ".";
|
||||
else if ((x-150)*(x-150)+(y-13)*(y-13) < 70)
|
||||
ret = "^";
|
||||
else if ((x-201)*(x-201)+(y-33)*(y-33) < 200)
|
||||
ret = "%";
|
||||
else if ((x-15)*(x-15)+(y-3)*(y-3) < 7)
|
||||
ret = "@";
|
||||
else
|
||||
ret = " ";
|
||||
return ret.charCodeAt(0) - 32;
|
||||
});
|
||||
|
||||
// randomImage: Nat Nat Nat Nat -> RectArray
|
||||
function randomImage(w, h, sparsity, variety) {
|
||||
return WrapArray.build(w, h, function (x,y) {
|
||||
if (Math.random() > 1/sparsity)
|
||||
return 0;
|
||||
else
|
||||
return 1+Math.random()*variety|0;
|
||||
});
|
||||
}
|
||||
|
||||
// stripedImage: Nat Nat -> RectArray
|
||||
function stripedImage(w, h) {
|
||||
return WrapArray.build(w, h,
|
||||
function (x, y) (Math.abs(x%100-y%100) < 10) ? 32 : 0);
|
||||
}
|
||||
|
||||
var massiveImage =
|
||||
WrapArray.build(70, 10000, function(x,y) (Math.abs(x%100-y%100) < 10) ? 32 : 0);
|
||||
|
||||
// asciiart: Self -> RectArray
|
||||
WrapArray.prototype.asciiart = function asciiart() {
|
||||
return this.map(function (x) String.fromCharCode(x+32));
|
||||
};
|
||||
|
||||
// row: Self Nat -> Array
|
||||
WrapArray.prototype.row = function row(i) {
|
||||
return this.slice(i*this.width*this.payload, (i+1)*this.width*this.payload);
|
||||
};
|
||||
|
||||
// render: Self -> String
|
||||
WrapArray.prototype.render = function render() {
|
||||
var art = this.asciiart();
|
||||
var a = new Array(art.height);
|
||||
for (var i=0; i < art.height; i++) {
|
||||
a[i] = art.row(i);
|
||||
}
|
||||
return a.map(function(r) r.join("")).join("\n");
|
||||
};
|
||||
|
||||
// print: Self -> void; effect: prints rendered self.
|
||||
WrapArray.prototype.print =
|
||||
(function locals() { var pr = print;
|
||||
return function print() pr(this.render()); })();
|
||||
|
||||
// toRectArray: Self Nat Nat -> RectArray
|
||||
Array.prototype.toRectArray = function toRectArray(w,h) {
|
||||
var p = this;
|
||||
return WrapArray.build(w, h, function (i, j) p[i+j*w]);
|
||||
};
|
||||
|
||||
WrapArray.prototype.toRectArray = function toRectArray(w,h) {
|
||||
var p = this;
|
||||
return WrapArray.build(w, h, function (i, j) p.get(i, j));
|
||||
};
|
||||
|
||||
// toRectArray: Self -> RectArray
|
||||
ParallelArray.prototype.toRectArray = function toRectArray(w, h) {
|
||||
var p = this;
|
||||
if (h == undefined) h = p.shape[1];
|
||||
if (w == undefined) w = p.shape[0];
|
||||
if (p.shape.length == 2)
|
||||
return WrapArray.build(w, h, function (i,j) p.get(i,j));
|
||||
if (p.shape.length == 1)
|
||||
return WrapArray.build(w, h, function (i,j) p.get(i + j*w));
|
||||
};
|
||||
|
||||
// toParallelArray: Self -> ParallelArray
|
||||
WrapArray.prototype.toParallelArray = function toParallelArray(mode) {
|
||||
var r = this;
|
||||
var w = this.width;
|
||||
var h = this.height;
|
||||
|
||||
if (false) {
|
||||
// This path is too slow...
|
||||
return new ParallelArray([w,h], function (i,j) r.get(i,j), mode);
|
||||
} else {
|
||||
// ...so resort to abstraction-breaking path here; yields >10x
|
||||
// speedup on Felix's Intel Core i7; but can we make above fast?
|
||||
var b = r.backingArray;
|
||||
return new ParallelArray([w,h], function (i,j) b[i+w*j], mode);
|
||||
}
|
||||
};
|
||||
|
||||
// transpose: Self -> RectArray
|
||||
WrapArray.prototype.transpose =
|
||||
function transpose() {
|
||||
var r = this;
|
||||
var b = r.backingArray;
|
||||
var w = r.width;
|
||||
return WrapArray.buildN(r.height, r.width, r.payload,
|
||||
function(x, y, k)
|
||||
// r.get(y,x,k)
|
||||
b[y+w*x]
|
||||
);
|
||||
};
|
||||
|
||||
// transpose: Self -> ParallelArray
|
||||
WrapArray.prototype.transposeParallelArray =
|
||||
function transpose(mode) {
|
||||
var r = this;
|
||||
var b = r.backingArray;
|
||||
var w = r.width;
|
||||
return new ParallelArray([r.height, r.width], function(x, y) b[y+w*x], mode);
|
||||
};
|
||||
|
||||
ParallelArray.prototype.transpose =
|
||||
function transpose(mode) {
|
||||
var p = this;
|
||||
var w = this.shape[0];
|
||||
var h = this.shape[1];
|
||||
return new ParallelArray([h,w], function (i,j) p.get(j,i), mode);
|
||||
};
|
||||
|
||||
// The detectEdgesSeq function allows edgesSequentially to be
|
||||
// implemented w/ sequential code directly rather than using a
|
||||
// ParMode to enforce sequential execution a la buildSequentially.)
|
||||
|
||||
// detectEdgesSeq_naive: RectArray -> RectArray
|
||||
// This version is naive because working directly on an array is
|
||||
// enormously faster.
|
||||
function detectEdgesSeq_naive(ra) {
|
||||
var sobelX = [[-1.0, 0.0, 1.0],
|
||||
[-2.0, 0.0, 2.0],
|
||||
[-1.0, 0.0, 1.0]];
|
||||
var sobelY = [[1.0, 2.0, 1.0],
|
||||
[0.0, 0.0, 0.0],
|
||||
[-1.0, -2.0, -1.0]];
|
||||
|
||||
var width = ra.width;
|
||||
var height = ra.height;
|
||||
|
||||
var abs = function(x) (x < 0) ? -x : x;
|
||||
return WrapArray.build(width, height,
|
||||
// The fill functions here and below are begging for refactoring, but leaving as manual clones until performance issues are resolved.
|
||||
function (x,y)
|
||||
{
|
||||
// process pixel
|
||||
var totalX = 0;
|
||||
var totalY = 0;
|
||||
for (var offY = -1; offY <= 1; offY++) {
|
||||
var newY = y + offY;
|
||||
for (var offX = -1; offX <= 1; offX++) {
|
||||
var newX = x + offX;
|
||||
if ((newX >= 0) && (newX < width) && (newY >= 0) && (newY < height)) {
|
||||
var pointIndex = (x + offX + (y + offY) * width);
|
||||
var e = ra.get(x + offX, y + offY);
|
||||
totalX += e * sobelX[offY + 1][offX + 1];
|
||||
totalY += e * sobelY[offY + 1][offX + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
var total = (abs(totalX) + abs(totalY))/8.0 | 0;
|
||||
return total;
|
||||
});
|
||||
}
|
||||
|
||||
// detectEdgesSeq_array_wh: Array Nat Nat -> Array
|
||||
// The input array needs to be carrying width and height properties, like RectArray
|
||||
function detectEdgesSeq_array_wh(data, width, height) {
|
||||
var data1 = new Array(width*height);
|
||||
var sobelX = [[-1.0, 0.0, 1.0],
|
||||
[-2.0, 0.0, 2.0],
|
||||
[-1.0, 0.0, 1.0]];
|
||||
var sobelY = [[1.0, 2.0, 1.0],
|
||||
[0.0, 0.0, 0.0],
|
||||
[-1.0, -2.0, -1.0]];
|
||||
|
||||
var abs = function(x) (x < 0) ? -x : x;
|
||||
for (var y = 0; y < height; y++) {
|
||||
for (var x = 0; x < width; x++) {
|
||||
// process pixel
|
||||
var totalX = 0;
|
||||
var totalY = 0;
|
||||
for (var offY = -1; offY <= 1; offY++) {
|
||||
var newY = y + offY;
|
||||
for (var offX = -1; offX <= 1; offX++) {
|
||||
var newX = x + offX;
|
||||
if ((newX >= 0) && (newX < width) && (newY >= 0) && (newY < height)) {
|
||||
var pointIndex = x + offX + (y + offY) * width;
|
||||
var e = data[pointIndex];
|
||||
totalX += e * sobelX[offY + 1][offX + 1];
|
||||
totalY += e * sobelY[offY + 1][offX + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
var total = ((abs(totalX) + abs(totalY))/8.0)|0;
|
||||
var index = y*width+x;
|
||||
data1[index] = total | 0;
|
||||
}
|
||||
}
|
||||
data1.width = width;
|
||||
data1.height = height;
|
||||
return data1;
|
||||
}
|
||||
|
||||
function detectEdgesSeq_wraparray(data) {
|
||||
return detectEdgesSeq_array_wh(data.backingArray, data.width, data.height);
|
||||
}
|
||||
|
||||
// detectEdges: Self -> RectArray
|
||||
WrapArray.prototype.detectEdges2D =
|
||||
(function locals () { var detect = detectEdgesSeq_array_wh;
|
||||
return function detectEdges() {
|
||||
return detect(this.backingArray, this.width, this.height).toRectArray(this.width, this.height);
|
||||
};
|
||||
})();
|
||||
|
||||
// detectEdgesPar: ParallelArray [ParMode] -> ParallelArray
|
||||
|
||||
function detectEdgesPar_2d(pa, mode)
|
||||
{
|
||||
var sobelX = [[-1.0, 0.0, 1.0],
|
||||
[-2.0, 0.0, 2.0],
|
||||
[-1.0, 0.0, 1.0]];
|
||||
var sobelY = [[1.0, 2.0, 1.0],
|
||||
[0.0, 0.0, 0.0],
|
||||
[-1.0, -2.0, -1.0]];
|
||||
|
||||
var width = pa.shape[0];
|
||||
var height = pa.shape[1];
|
||||
|
||||
var abs = function(x) (x < 0) ? -x : x;
|
||||
var ret=new ParallelArray([width, height],
|
||||
function (x,y)
|
||||
{
|
||||
// process pixel
|
||||
var totalX = 0;
|
||||
var totalY = 0;
|
||||
for (var offY = -1; offY <= 1; offY++) {
|
||||
var newY = y + offY;
|
||||
for (var offX = -1; offX <= 1; offX++) {
|
||||
var newX = x + offX;
|
||||
if ((newX >= 0) && (newX < width) && (newY >= 0) && (newY < height)) {
|
||||
var pointIndex = (x + offX + (y + offY) * width);
|
||||
var e = pa.get(x + offX, y + offY);
|
||||
totalX += e * sobelX[offY + 1][offX + 1];
|
||||
totalY += e * sobelY[offY + 1][offX + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
var total = (abs(totalX) + abs(totalY))/8.0 | 0;
|
||||
return total;
|
||||
}, mode);
|
||||
ret.width = width;
|
||||
ret.height = height;
|
||||
return ret;
|
||||
}
|
||||
|
||||
function detectEdgesPar_1d(pa, mode)
|
||||
{
|
||||
var sobelX = [[-1.0, 0.0, 1.0],
|
||||
[-2.0, 0.0, 2.0],
|
||||
[-1.0, 0.0, 1.0]];
|
||||
var sobelY = [[1.0, 2.0, 1.0],
|
||||
[0.0, 0.0, 0.0],
|
||||
[-1.0, -2.0, -1.0]];
|
||||
|
||||
var width = pa.shape[0];
|
||||
var height = pa.shape[1];
|
||||
|
||||
var abs = function(x) (x < 0) ? -x : x;
|
||||
|
||||
var ret=new ParallelArray(width*height,
|
||||
function (index)
|
||||
{
|
||||
var j = index | 0;
|
||||
var y = (j / width) | 0;
|
||||
var x = (j % width);
|
||||
// process pixel
|
||||
var totalX = 0;
|
||||
var totalY = 0;
|
||||
for (var offY = -1; offY <= 1; offY++) {
|
||||
var newY = y + offY;
|
||||
for (var offX = -1; offX <= 1; offX++) {
|
||||
var newX = x + offX;
|
||||
if ((newX >= 0) && (newX < width) && (newY >= 0) && (newY < height)) {
|
||||
var pointIndex = (x + offX + (y + offY) * width);
|
||||
var e = pa.get(x + offX, y + offY);
|
||||
totalX += e * sobelX[offY + 1][offX + 1];
|
||||
totalY += e * sobelY[offY + 1][offX + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
var total = (abs(totalX) + abs(totalY))/8.0 | 0;
|
||||
return total;
|
||||
}, mode);
|
||||
|
||||
ret.width = width;
|
||||
ret.height = height;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// detectEdges: Self [ParMode] -> ParallelArray
|
||||
ParallelArray.prototype.detectEdges2D =
|
||||
(function locals () { var detect = detectEdgesPar_2d;
|
||||
return function detectEdges(mode) detect(this, mode); })();
|
||||
|
||||
ParallelArray.prototype.detectEdges1D =
|
||||
(function locals () { var detect = detectEdgesPar_1d;
|
||||
return function detectEdges(mode) detect(this, mode); })();
|
||||
|
||||
// computeEnergy: ParallelArray -> RectArray
|
||||
//
|
||||
// (The return type is forced upon us, for now at least, until we add
|
||||
// appropriate API to ParallelArray; there's a dependency from each
|
||||
// row upon its predecessor, but the contents of each row could be
|
||||
// computed in parallel.)
|
||||
function computeEnergy_2d(source, width, height) {
|
||||
var energy = new WrapArray(width, height);
|
||||
energy.set(0, 0, 0);
|
||||
for (var y = 0; y < height; y++) {
|
||||
for (var x = 0; x < width; x++) {
|
||||
var e = source.get(x, y);
|
||||
if (y >= 1) {
|
||||
var p = energy.get(x, y-1);
|
||||
if (x > 0) {
|
||||
p = Math.min(p, energy.get(x-1, y-1));
|
||||
}
|
||||
if (x < (width - 1)) {
|
||||
p = Math.min(p, energy.get(x+1, y-1));
|
||||
}
|
||||
e += p;
|
||||
}
|
||||
energy.set(x, y, e);
|
||||
}
|
||||
}
|
||||
return energy;
|
||||
}
|
||||
|
||||
function computeEnergy_1d(source, width, height) {
|
||||
var energy = new WrapArray(width, height);
|
||||
energy.set(0, 0, 0);
|
||||
for (var y = 0; y < height; y++) {
|
||||
for (var x = 0; x < width; x++) {
|
||||
var e = source.get(x + y*width);
|
||||
if (y >= 1) {
|
||||
var p = energy.get(x, (y-1));
|
||||
if (x > 0) {
|
||||
p = Math.min(p, energy.get(x-1, (y-1)));
|
||||
}
|
||||
if (x < (width - 1)) {
|
||||
p = Math.min(p, energy.get(x+1, (y-1)));
|
||||
}
|
||||
e += p;
|
||||
}
|
||||
energy.set(x, y, e);
|
||||
}
|
||||
}
|
||||
return energy;
|
||||
}
|
||||
|
||||
// computeEnergy: Self -> RectArray
|
||||
WrapArray.prototype.computeEnergy =
|
||||
(function locals () { var energy = computeEnergy_2d;
|
||||
return function computeEnergy() energy(this, this.width, this.height); })();
|
||||
|
||||
// computeEnergy: Self -> RectArray
|
||||
ParallelArray.prototype.computeEnergy =
|
||||
(function locals () {
|
||||
var energy1d = computeEnergy_1d;
|
||||
var energy2d = computeEnergy_2d;
|
||||
return function computeEnergy()
|
||||
(this.shape.length == 2)
|
||||
? energy2d(this, this.width, this.height)
|
||||
: energy1d(this, this.width, this.height); })();
|
||||
|
||||
// findPath: RectArray -> Array
|
||||
// (This is inherently sequential.)
|
||||
function findPath(energy)
|
||||
{
|
||||
var height = energy.height;
|
||||
var width = energy.width;
|
||||
var path = new Array(height);
|
||||
var y = height - 1;
|
||||
var minPos = 0;
|
||||
var minEnergy = energy.get(minPos, y);
|
||||
|
||||
for (var x = 1; x < width; x++) {
|
||||
if (energy.get(x,y) < minEnergy) {
|
||||
minEnergy = energy.get(x,y);
|
||||
minPos = x;
|
||||
}
|
||||
}
|
||||
|
||||
path[y] = minPos;
|
||||
for (y = height - 2; y >= 0; y--) {
|
||||
minEnergy = energy.get(minPos, y);
|
||||
// var line = energy[y]
|
||||
var p = minPos;
|
||||
if (p >= 1 && energy.get(p-1, y) < minEnergy) {
|
||||
minPos = p-1; minEnergy = energy.get(p-1, y);
|
||||
}
|
||||
if (p < width - 1 && energy.get(p+1, y) < minEnergy) {
|
||||
minPos = p+1; minEnergy = energy.get(p+1, y);
|
||||
}
|
||||
path[y] = minPos;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
// findPath: Self -> Path
|
||||
WrapArray.prototype.findPath =
|
||||
(function locals() { var path = findPath;
|
||||
return function findPath() path(this); })();
|
||||
|
||||
// cutPathHorizontallyBW : RectArray Array -> RectArray
|
||||
function cutPathHorizontallyBW(ra, path) {
|
||||
return WrapArray.build(ra.width-1, ra.height,
|
||||
function (x, y) {
|
||||
if (x < path[y]-1)
|
||||
return ra.get(x, y);
|
||||
if (x == path[y]-1)
|
||||
return (ra.get(x,y)+ra.get(x+1,y))/2|0;
|
||||
else
|
||||
return ra.get(x+1,y);
|
||||
});
|
||||
}
|
||||
|
||||
// cutPathHorizontallyBW: Self -> RectArray
|
||||
WrapArray.prototype.cutPathHorizontallyBW =
|
||||
(function locals() { var cut = cutPathHorizontallyBW;
|
||||
return function cutPathHorizontallyBW(path) cut(this, path); })();
|
||||
|
||||
// cutPathVerticallyBW: RectArray Path -> RectArray
|
||||
function cutPathVerticallyBW(ra, path) {
|
||||
return WrapArray.build(ra.width, ra.height-1,
|
||||
function (x, y) {
|
||||
if (y < path[x]-1)
|
||||
return ra.get(x, y);
|
||||
if (y == path[x]-1)
|
||||
return (ra.get(x,y)+ra.get(x,y+1))/2|0;
|
||||
else
|
||||
return ra.get(x,y+1);
|
||||
});
|
||||
}
|
||||
|
||||
// cutPathVerticallyBW: Self Path -> RectArray
|
||||
WrapArray.prototype.cutPathVerticallyBW =
|
||||
(function locals() { var cut = cutPathVerticallyBW;
|
||||
return function cutPathVerticallyBW(path) cut(this, path); })();
|
||||
|
||||
// cutHorizontalSeamBW: RectArray ParMode -> RectArray
|
||||
|
||||
function cutHorizontalSeamBW_seq(r)
|
||||
{
|
||||
var e = r.detectEdges2D().computeEnergy();
|
||||
var p = e.findPath(); e = null;
|
||||
return r.cutPathHorizontallyBW(p);
|
||||
}
|
||||
|
||||
function cutHorizontalSeamBW_par(r, mode)
|
||||
{
|
||||
var e = r.toParallelArray(mode).detectEdges1D(mode).computeEnergy(mode);
|
||||
var p = e.findPath(mode); e = null;
|
||||
return r.cutPathHorizontallyBW(p, mode);
|
||||
}
|
||||
|
||||
// cutHorizontalSeamBW: Self ParMode -> RectArray
|
||||
WrapArray.prototype.cutHorizontalSeamBW =
|
||||
(function locals() {
|
||||
var cut_seq = cutHorizontalSeamBW_seq;
|
||||
var cut_par = cutHorizontalSeamBW_par;
|
||||
return function cutHorizontalSeamBW(mode) {
|
||||
return (mode ? cut_par(this, mode) : cut_seq(this));
|
||||
};})();
|
||||
|
||||
// cutVerticalSeamBW: RectArray ParMode -> RectArray
|
||||
function cutVerticalSeamBW_seq(r)
|
||||
{
|
||||
var e = r.transpose().detectEdges2D().computeEnergy();
|
||||
return r.cutPathVerticallyBW(e.findPath());
|
||||
}
|
||||
|
||||
function cutVerticalSeamBW_par(r, mode)
|
||||
{
|
||||
var e = r.transposeParallelArray(mode).detectEdges1D(mode).computeEnergy(mode);
|
||||
return r.cutPathVerticallyBW(e.findPath());
|
||||
}
|
||||
|
||||
// cutVerticalSeamBW: Self ParMode -> RectArray
|
||||
WrapArray.prototype.cutVerticalSeamBW =
|
||||
(function locals() {
|
||||
var cut_seq = cutVerticalSeamBW_seq;
|
||||
var cut_par = cutVerticalSeamBW_par;
|
||||
return function cutVerticalSeamBW(mode) {
|
||||
return (mode ? cut_par(this, mode) : cut_seq(this));
|
||||
};})();
|
||||
|
||||
// cutVerticalSeamBW: Self Nat Nat ParMode -> Self
|
||||
WrapArray.prototype.shrinkBW = function shrinkBW(w, h, mode) {
|
||||
if (w == undefined)
|
||||
w = this.width / 2 | 0;
|
||||
if (h == undefined)
|
||||
h = this.height / 2 | 0;
|
||||
var r = this;
|
||||
var i=0;
|
||||
while (r.height > h || r.width > w) {
|
||||
if (i > 0 && i%50 == 0) { print("shrinkBW iteration "+i); } i++;
|
||||
if (r.width > w)
|
||||
r = r.cutHorizontalSeamBW(mode);
|
||||
if (r.height > h)
|
||||
r = r.cutVerticalSeamBW(mode);
|
||||
}
|
||||
return r;
|
||||
};
|
||||
|
||||
// timedShrinkBW: Self Nat Nat ParMode -> PhaseTimes
|
||||
WrapArray.prototype.timedShrinkBW = function timedShrinkBW(w, h, mode) {
|
||||
var times = {
|
||||
"topar": 0, "trans": 0, "edges": 0, "energ": 0, "fpath": 0, "cpath": 0
|
||||
};
|
||||
var r = this;
|
||||
var lasttime = new Date();
|
||||
function elapsed() {
|
||||
var d = new Date(); var e = d - lasttime; lasttime = d; return e;
|
||||
}
|
||||
if (mode) {
|
||||
while (r.height > h || r.width > w) {
|
||||
if (r.width > w) {
|
||||
elapsed();
|
||||
var e = r.toParallelArray(mode);
|
||||
times.topar += elapsed();
|
||||
e = e.detectEdges1D(mode);
|
||||
times.edges += elapsed();
|
||||
e = e.computeEnergy(mode);
|
||||
times.energ += elapsed();
|
||||
e = e.findPath(mode);
|
||||
times.fpath += elapsed();
|
||||
r = r.cutPathHorizontallyBW(e, mode);
|
||||
times.cpath += elapsed();
|
||||
e = null;
|
||||
}
|
||||
if (r.height > h) {
|
||||
elapsed();
|
||||
var e = r.transposeParallelArray(mode);
|
||||
times.trans += elapsed();
|
||||
e = e.detectEdges1D(mode);
|
||||
times.edges += elapsed();
|
||||
e = e.computeEnergy(mode);
|
||||
times.energ += elapsed();
|
||||
e = e.findPath(mode);
|
||||
times.fpath += elapsed();
|
||||
r = r.cutPathVerticallyBW(e, mode);
|
||||
times.cpath += elapsed();
|
||||
e = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (r.height > h || r.width > w) {
|
||||
if (r.width > w) {
|
||||
elapsed();
|
||||
var e = r.detectEdges2D();
|
||||
times.edges += elapsed();
|
||||
e = e.computeEnergy();
|
||||
times.energ += elapsed();
|
||||
var p = e.findPath(); e = null;
|
||||
times.fpath += elapsed();
|
||||
r = r.cutPathHorizontallyBW(p);
|
||||
times.cpath += elapsed();
|
||||
e = null; p = null;
|
||||
}
|
||||
if (r.height > h) {
|
||||
elapsed();
|
||||
var e = r.transpose();
|
||||
times.trans += elapsed();
|
||||
e = e.detectEdges2D();
|
||||
times.edges += elapsed();
|
||||
e = e.computeEnergy();
|
||||
times.energ += elapsed();
|
||||
var p = e.findPath(); e = null;
|
||||
times.fpath += elapsed();
|
||||
r = r.cutPathVerticallyBW(p);
|
||||
times.cpath += elapsed();
|
||||
}
|
||||
}
|
||||
}
|
||||
return times;
|
||||
};
|
||||
|
||||
function timedDetectEdges2D(mode) {
|
||||
var d = new Date(); this.detectEdges2D(mode); var e = new Date(); return e - d;
|
||||
};
|
||||
|
||||
function timedDetectEdges1D(mode) {
|
||||
var d = new Date(); this.detectEdges1D(mode); var e = new Date(); return e - d;
|
||||
};
|
||||
|
||||
WrapArray.prototype.timedDetectEdges2D = timedDetectEdges2D;
|
||||
ParallelArray.prototype.timedDetectEdges2D = timedDetectEdges2D;
|
||||
ParallelArray.prototype.timedDetectEdges1D = timedDetectEdges1D;
|
||||
|
||||
if (benchmarking) {
|
||||
// Below functions are to interface with run.sh
|
||||
|
||||
// For simple, repeatable investigation, use: tinyImage, smallImage,
|
||||
// bigImage, or massiveImage for expression establishing seqInput
|
||||
// below. stripedImage() is also useful for repeatable inputs.
|
||||
//
|
||||
// For play, use: randomImage(width, height, sparsity, variety)
|
||||
// or stripedImage(width, height).
|
||||
//
|
||||
// The default tower image from the original benchmarks was 800x542.
|
||||
// (Correspondingly, the shrunken versions were 400x271 and 80x54.)
|
||||
var seqInput = stripedImage(800/4|0, 542/4|0, 10, 10);
|
||||
var parInput = seqInput.toParallelArray();
|
||||
|
||||
function buildSequentially() {
|
||||
return seqInput.toParallelArray({mode:"seq"});
|
||||
}
|
||||
function buildParallel() {
|
||||
return seqInput.toParallelArray({mode:"par"});
|
||||
}
|
||||
|
||||
function edgesSequentially() {
|
||||
return detectEdgesSeq_wraparray(seqInput);
|
||||
}
|
||||
function edgesParallel() {
|
||||
return detectEdgesPar_1d(parInput);
|
||||
}
|
||||
|
||||
function resizSequentially() {
|
||||
var input = seqInput;
|
||||
return input.shrinkBW(input.width/2|0, input.height/2|0);
|
||||
}
|
||||
function resizParallel() {
|
||||
var input = seqInput; // Use of "seqInput" here is deliberate, as
|
||||
// the above code does not add a shrinkBW
|
||||
// method to ParallelArray.prototype (we
|
||||
// are going to marshall repeatedly in the
|
||||
// loop within shrinkBW anyway).
|
||||
return input.shrinkBW(input.width/2|0, input.height/2|0, {mode:"par"});
|
||||
}
|
||||
|
||||
if (benchmarking) {
|
||||
benchmark("BUILD", 1, DEFAULT_MEASURE,
|
||||
buildSequentially, buildParallel);
|
||||
|
||||
benchmark("EDGES", 1, DEFAULT_MEASURE,
|
||||
edgesSequentially, edgesParallel);
|
||||
|
||||
benchmark("RESIZ", 1, DEFAULT_MEASURE,
|
||||
resizSequentially, resizParallel);
|
||||
}
|
||||
}
|
315
js/src/parjs-benchmarks/rectarray.js
Normal file
315
js/src/parjs-benchmarks/rectarray.js
Normal file
@ -0,0 +1,315 @@
|
||||
// -*- mode: js2; indent-tabs-mode: nil; -*-
|
||||
|
||||
// A RectArray<X,k> is a subclass of Array with 'width', 'height',
|
||||
// and 'payload' properties (where payload holds 'k').
|
||||
// properties, and 'width*height*k' elements (each an X) in the array.
|
||||
//
|
||||
// A RectTypedByteArray<k> is a subclass of ArrayBuffer with 'width'
|
||||
// and 'height' properties, and 'width*height*k' bytes in the buffer.
|
||||
//
|
||||
// The 'payload' property is initialized with the value of 'k'.
|
||||
//
|
||||
// (Felix would have used Array or ArrayView, but for the following bug:
|
||||
// Bug 695438 - TypedArrays don't support new named properties
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=695438
|
||||
// and so he is resorting to extending ArrayBuffer instead.)
|
||||
//
|
||||
// Both classes add a .get(x,y[,k]) method that eases access to the
|
||||
// contents, and a set(x,y[,k],value) method that eases modifying
|
||||
// their entries.
|
||||
//
|
||||
// In addition, for those who prefer functional-style,
|
||||
// RectArray.build,
|
||||
// and RectByteTypedArray.build
|
||||
|
||||
var RectArray, RectByteTypedArray;
|
||||
|
||||
// This is a variant of RectArray that supports the same interface,
|
||||
// but instead of attempting to extend Array (a practice fraught with
|
||||
// peril), it instead makes a wrapper around another array.
|
||||
|
||||
var WrapArray, WrapByteTypedArray;
|
||||
|
||||
(function (){
|
||||
|
||||
function defineReadOnly(x, name, value) {
|
||||
Object.defineProperty(x, name, {
|
||||
value: value,
|
||||
writable: false,
|
||||
enumerable: true,
|
||||
configurable: true });
|
||||
}
|
||||
|
||||
RectArray = function RectArray(w,h,k) {
|
||||
if (k === undefined)
|
||||
k = 1;
|
||||
this.length = w*h*k;
|
||||
defineReadOnly(this, "width", w);
|
||||
defineReadOnly(this, "height", h);
|
||||
defineReadOnly(this, "payload", k);
|
||||
};
|
||||
|
||||
RectByteTypedArray = function RectByteTypedArray(w,h,k) {
|
||||
if (k === undefined)
|
||||
k = 1;
|
||||
ArrayBuffer.call(this, w*h*k);
|
||||
defineReadOnly(this, "width", w);
|
||||
defineReadOnly(this, "height", h);
|
||||
defineReadOnly(this, "payload", k);
|
||||
};
|
||||
|
||||
WrapArray = function WrapArray(w,h,k) {
|
||||
if (k === undefined)
|
||||
k = 1;
|
||||
this.backingArray = new Array(w*h*k);
|
||||
defineReadOnly(this, "width", w);
|
||||
defineReadOnly(this, "height", h);
|
||||
defineReadOnly(this, "payload", k);
|
||||
};
|
||||
|
||||
WrapByteTypedArray = function WrapByteTypedArray(w,h,k) {
|
||||
if (k === undefined)
|
||||
k = 1;
|
||||
this.backingArray = new Uint8Array(new ArrayBuffer(w*h*k));
|
||||
defineReadOnly(this, "width", w);
|
||||
defineReadOnly(this, "height", h);
|
||||
defineReadOnly(this, "payload", k);
|
||||
};
|
||||
|
||||
WrapArray.prototype.slice = function(a,b) this.backingArray.slice(a,b);
|
||||
WrapArray.prototype.join = function(a) this.backingArray.join(a);
|
||||
|
||||
RectArray.prototype = new Array();
|
||||
RectByteTypedArray.prototype = new ArrayBuffer();
|
||||
|
||||
RectArray.prototype.get = function get(x,y,j) {
|
||||
if (j === undefined) j = 0;
|
||||
return this[(y*this.width+x)*this.payload+j];
|
||||
};
|
||||
|
||||
RectArray.prototype.set = function set(x,y,j,value) {
|
||||
if (value === undefined) {
|
||||
value = j;
|
||||
j = 0;
|
||||
}
|
||||
this[(y*this.width+x)*this.payload+j] = value;
|
||||
};
|
||||
|
||||
RectByteTypedArray.prototype.get = function get(x,y,j) {
|
||||
if (j === undefined) j = 0;
|
||||
return (new Uint8Array(this))[(y*this.width+x)*this.payload+j];
|
||||
};
|
||||
|
||||
RectByteTypedArray.prototype.set = function set(x,y,j,value) {
|
||||
if (value === undefined) {
|
||||
value = j;
|
||||
j = 0;
|
||||
}
|
||||
(new Uint8Array(this))[(y*this.width+x)*this.payload+j] = value;
|
||||
};
|
||||
|
||||
WrapArray.prototype.get = function get(x,y,j) {
|
||||
if (j === undefined) j = 0;
|
||||
return this.backingArray[(y*this.width+x)*this.payload+j];
|
||||
};
|
||||
|
||||
WrapArray.prototype.set = function set(x,y,j,value) {
|
||||
if (value === undefined) {
|
||||
value = j;
|
||||
j = 0;
|
||||
}
|
||||
this.backingArray[(y*this.width+x)*this.payload+j] = value;
|
||||
};
|
||||
|
||||
WrapByteTypedArray.prototype.get = function get(x,y,j) {
|
||||
if (j === undefined) j = 0;
|
||||
return this.backingArray[(y*this.width+x)*this.payload+j];
|
||||
};
|
||||
|
||||
WrapByteTypedArray.prototype.set = function set(x,y,j,value) {
|
||||
if (value === undefined) {
|
||||
value = j;
|
||||
j = 0;
|
||||
}
|
||||
this.backingArray[(y*this.width+x)*this.payload+j] = value;
|
||||
};
|
||||
|
||||
function viewToSource(view, width, height, payload) {
|
||||
var ret = "[";
|
||||
var i=0;
|
||||
var matrixNeedsNewline = false;
|
||||
for (var row=0; row < height; row++) {
|
||||
if (matrixNeedsNewline)
|
||||
ret += ",\n ";
|
||||
ret += "[";
|
||||
var rowNeedsComma = false;
|
||||
for (var x=0; x < width; x++) {
|
||||
if (rowNeedsComma)
|
||||
ret += ", ";
|
||||
if (payload == 1) {
|
||||
if (view[i] !== undefined)
|
||||
ret += view[i];
|
||||
i++;
|
||||
} else {
|
||||
var entryNeedsComma = false;
|
||||
ret += "(";
|
||||
for (var k=0; k < payload; k++) {
|
||||
// Might be inefficient (does JavaScript have
|
||||
// StringBuffers?, or use them internally, like Tamarin?)
|
||||
if (entryNeedsComma)
|
||||
ret += ", ";
|
||||
if (view[i] !== undefined)
|
||||
ret += view[i];
|
||||
entryNeedsComma = true;
|
||||
i++;
|
||||
}
|
||||
ret += ")";
|
||||
}
|
||||
rowNeedsComma = true;
|
||||
}
|
||||
ret += "]";
|
||||
matrixNeedsNewline = true;
|
||||
}
|
||||
ret += "]";
|
||||
return ret;
|
||||
}
|
||||
|
||||
RectArray.prototype.toSource = function toSource() {
|
||||
return viewToSource(this,
|
||||
this.width, this.height, this.payload);
|
||||
};
|
||||
|
||||
RectByteTypedArray.prototype.toSource = function toSource() {
|
||||
return viewToSource(new Uint8Array(this),
|
||||
this.width, this.height, this.payload);
|
||||
};
|
||||
|
||||
WrapArray.prototype.toSource = function toSource() {
|
||||
return viewToSource(this.backingArray,
|
||||
this.width, this.height, this.payload);
|
||||
};
|
||||
|
||||
WrapByteTypedArray.prototype.toSource = function toSource() {
|
||||
return viewToSource(this.backingArray,
|
||||
this.width, this.height, this.payload);
|
||||
};
|
||||
|
||||
RectArray.prototype.map = function map(f) {
|
||||
var ret = Array.map(this, f);
|
||||
ret.__proto__ = RectArray.prototype;
|
||||
defineReadOnly(ret, "width", this.width);
|
||||
defineReadOnly(ret, "height", this.height);
|
||||
defineReadOnly(ret, "payload", this.payload);
|
||||
return ret;
|
||||
};
|
||||
|
||||
WrapArray.prototype.map = function map(f) {
|
||||
var ret = new WrapArray(this.width, this.height, this.payload);
|
||||
ret.backingArray = this.backingArray.map(f);
|
||||
return ret;
|
||||
};
|
||||
|
||||
// (Array<X>|ArrayView<X>) Nat Nat Nat (Nat Nat Nat -> X) -> void
|
||||
function fillArrayView(view, width, height, k, fill) {
|
||||
var i = 0;
|
||||
for (var y=0; y < height; y++) {
|
||||
for (var x=0; x < width; x++) {
|
||||
for (var j=0; j < k; j++) {
|
||||
view[i++] = fill(x, y, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Nat Nat (Nat Nat [Nat] -> X) -> RectArray<X,1>
|
||||
RectArray.build =
|
||||
function buildRectArray1(width, height, fill) {
|
||||
var a = new RectArray(width, height, 1);
|
||||
fillArrayView(a, width, height, 1, fill);
|
||||
return a;
|
||||
};
|
||||
|
||||
RectArray.buildA =
|
||||
function buildRectArrayA(width, height, fill) {
|
||||
var a = new Array(width*height);
|
||||
fillArrayView(a, width, height, 1, fill);
|
||||
a.width = width;
|
||||
a.height = height;
|
||||
a.payload = 1;
|
||||
function F() { }
|
||||
F.prototype = RectArray.prototype;
|
||||
a.__proto__ = new F();
|
||||
return a;
|
||||
};
|
||||
|
||||
// Nat Nat (Nat Nat Nat -> X) -> RectArray<X,4>
|
||||
RectArray.build4 =
|
||||
function buildRectArray4(width, height, fill) {
|
||||
var a = new RectArray(width, height, 4);
|
||||
fillArrayView(a, width, height, 4, fill);
|
||||
return a;
|
||||
};
|
||||
|
||||
// Nat Nat (Nat Nat Nat -> X) -> RectArray<X,1>
|
||||
RectArray.buildN =
|
||||
function buildRectArrayN(width, height, n, fill) {
|
||||
var a = new RectArray(width, height, n);
|
||||
fillArrayView(a, width, height, n, fill);
|
||||
return a;
|
||||
};
|
||||
|
||||
|
||||
// Nat Nat (Nat Nat [Nat] -> Byte) -> RectTypedByteArray<4>
|
||||
RectByteTypedArray.build =
|
||||
function buildRectByteTypedArray1(width, height, fill) {
|
||||
var buf = new RectByteTypedArray(width, height, 1);
|
||||
fillArrayView(new Uint8Array(buf), width, height, 1, fill);
|
||||
return buf;
|
||||
};
|
||||
|
||||
// Nat Nat (Nat Nat Nat -> Byte) -> RectTypedByteArray<4>
|
||||
RectByteTypedArray.build4 =
|
||||
function buildRectByteTypedArray4(width, height, fill) {
|
||||
var buf = new RectByteTypedArray(width, height, 4);
|
||||
fillArrayView(new Uint8Array(buf), width, height, 4, fill);
|
||||
return buf;
|
||||
};
|
||||
|
||||
// Nat Nat (Nat Nat Nat -> Byte) -> RectTypedByteArray<4>
|
||||
RectByteTypedArray.buildN =
|
||||
function buildRectByteTypedArray4(width, height, n, fill) {
|
||||
var buf = new RectByteTypedArray(width, height, n);
|
||||
fillArrayView(new Uint8Array(buf), width, height, n, fill);
|
||||
return buf;
|
||||
};
|
||||
|
||||
WrapArray.build =
|
||||
function buildWrapArray1(width, height, fill) {
|
||||
var a = new WrapArray(width, height, 1);
|
||||
fillArrayView(a, width, height, 1, fill);
|
||||
return a;
|
||||
};
|
||||
|
||||
WrapArray.build =
|
||||
function buildWrapArray1(width, height, fill) {
|
||||
var a = new WrapArray(width, height, 1);
|
||||
fillArrayView(a.backingArray, width, height, 1, fill);
|
||||
return a;
|
||||
};
|
||||
|
||||
WrapArray.build4 =
|
||||
function buildWrapArray1(width, height, fill) {
|
||||
var a = new WrapArray(width, height, 4);
|
||||
fillArrayView(a.backingArray, width, height, 4, fill);
|
||||
return a;
|
||||
};
|
||||
|
||||
WrapArray.buildN =
|
||||
function buildWrapArray1(width, height, n, fill) {
|
||||
var a = new WrapArray(width, height, n);
|
||||
fillArrayView(a.backingArray, width, height, n, fill);
|
||||
return a;
|
||||
};
|
||||
|
||||
})();
|
@ -2,6 +2,13 @@ DEFAULT_WARMUP = 10
|
||||
DEFAULT_MEASURE = 3
|
||||
MODE = MODE || "compare" // MODE is often set on the command-line by run.sh
|
||||
|
||||
/**
|
||||
* label: for the printouts
|
||||
* w: warmup runs
|
||||
* m: measurement runs
|
||||
* seq: closure to compute sequentially
|
||||
* par: closure to compute in parallel
|
||||
*/
|
||||
function benchmark(label, w, m, seq, par) {
|
||||
var SEQ = 1
|
||||
var PAR = 2
|
||||
@ -51,7 +58,7 @@ function benchmark(label, w, m, seq, par) {
|
||||
if (mode(SEQ|PAR)) {
|
||||
print(label + " SEQ/PAR RATIO : " + seqAvg/parAvg);
|
||||
print(label + " PAR/SEQ RATIO : " + parAvg/seqAvg);
|
||||
print(label + " SPEEDUP : " +
|
||||
print(label + " IMPROVEMENT : " +
|
||||
(((seqAvg - parAvg) / seqAvg * 100.0) | 0) + "%");
|
||||
}
|
||||
|
||||
@ -94,10 +101,28 @@ function measureN(iters, f) {
|
||||
function assertStructuralEq(e1, e2) {
|
||||
if (e1 instanceof ParallelArray && e2 instanceof ParallelArray) {
|
||||
assertEqParallelArray(e1, e2);
|
||||
} else if (typeof(RectArray) != "undefined" &&
|
||||
e1 instanceof ParallelArray && e2 instanceof RectArray) {
|
||||
assertEqParallelArrayRectArray(e1, e2);
|
||||
} else if (typeof(RectArray) != "undefined" &&
|
||||
e1 instanceof RectArray && e2 instanceof ParallelArray) {
|
||||
assertEqParallelArrayRectArray(e2, e1);
|
||||
} else if (typeof(WrapArray) != "undefined" &&
|
||||
e1 instanceof ParallelArray && e2 instanceof WrapArray) {
|
||||
assertEqParallelArrayWrapArray(e1, e2);
|
||||
} else if (typeof(WrapArray) != "undefined" &&
|
||||
e1 instanceof WrapArray && e2 instanceof ParallelArray) {
|
||||
assertEqParallelArrayWrapArray(e2, e1);
|
||||
} else if (e1 instanceof Array && e2 instanceof ParallelArray) {
|
||||
assertEqParallelArrayArray(e2, e1);
|
||||
} else if (e1 instanceof ParallelArray && e2 instanceof Array) {
|
||||
assertEqParallelArrayArray(e1, e2);
|
||||
} else if (typeof(RectArray) != "undefined" &&
|
||||
e1 instanceof RectArray && e2 instanceof RectArray) {
|
||||
assertEqRectArray(e1, e2);
|
||||
} else if (typeof(WrapArray) != "undefined" &&
|
||||
e1 instanceof WrapArray && e2 instanceof WrapArray) {
|
||||
assertEqWrapArray(e1, e2);
|
||||
} else if (e1 instanceof Array && e2 instanceof Array) {
|
||||
assertEqArray(e1, e2);
|
||||
} else if (e1 instanceof Object && e2 instanceof Object) {
|
||||
@ -113,6 +138,28 @@ function assertStructuralEq(e1, e2) {
|
||||
}
|
||||
}
|
||||
|
||||
function assertEqParallelArrayRectArray(a, b) {
|
||||
assertEq(a.shape.length, 2);
|
||||
assertEq(a.shape[0], b.width);
|
||||
assertEq(a.shape[1], b.height);
|
||||
for (var i = 0, w = a.shape[0]; i < w; i++) {
|
||||
for (var j = 0, h = a.shape[1]; j < h; j++) {
|
||||
assertStructuralEq(a.get(i,j), b.get(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertEqParallelArrayWrapArray(a, b) {
|
||||
assertEq(a.shape.length, 2);
|
||||
assertEq(a.shape[0], b.width);
|
||||
assertEq(a.shape[1], b.height);
|
||||
for (var i = 0, w = a.shape[0]; i < w; i++) {
|
||||
for (var j = 0, h = a.shape[1]; j < h; j++) {
|
||||
assertStructuralEq(a.get(i,j), b.get(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertEqParallelArrayArray(a, b) {
|
||||
assertEq(a.shape.length, 1);
|
||||
assertEq(a.length, b.length);
|
||||
@ -121,6 +168,26 @@ function assertEqParallelArrayArray(a, b) {
|
||||
}
|
||||
}
|
||||
|
||||
function assertEqRectArray(a, b) {
|
||||
assertEq(a.width, b.width);
|
||||
assertEq(a.height, b.height);
|
||||
for (var i = 0, w = a.width; i < w; i++) {
|
||||
for (var j = 0, h = a.height; j < h; j++) {
|
||||
assertStructuralEq(a.get(i,j), b.get(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertEqWrapArray(a, b) {
|
||||
assertEq(a.width, b.width);
|
||||
assertEq(a.height, b.height);
|
||||
for (var i = 0, w = a.width; i < w; i++) {
|
||||
for (var j = 0, h = a.height; j < h; j++) {
|
||||
assertStructuralEq(a.get(i,j), b.get(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertEqArray(a, b) {
|
||||
assertEq(a.length, b.length);
|
||||
for (var i = 0, l = a.length; i < l; i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user