summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorCharlie Gordon <github@chqrlie.org>2024-02-26 00:14:31 +0100
committerCharlie Gordon <github@chqrlie.org>2024-02-26 00:14:31 +0100
commit8180d3dd879aeafa9fcd479ad174de88e73b3d15 (patch)
tree692c16f20255c9f77bf2b26c94ee5307b7648af6 /tests
parent78db49cf9543b983d5f0edf361cbfe907451c826 (diff)
downloadquickjs-8180d3dd879aeafa9fcd479ad174de88e73b3d15.tar.gz
quickjs-8180d3dd879aeafa9fcd479ad174de88e73b3d15.zip
Improve microbench.js
- ensure handler behavior does not depend on n argument - load and save reference file in node.js - add -s filename option to name the output reference file - add targets in Makefile for tests and bencharks using node.js - fix incorrect timings when not using high resolution timer - use performance timer in node.js - output performance factor instead of percentage - use smaller threshold by default - add benchmarks for: date_parse(), prop_update(), prop_clone(), array_slice() global_func_call(),
Diffstat (limited to 'tests')
-rw-r--r--tests/microbench.js375
1 files changed, 276 insertions, 99 deletions
diff --git a/tests/microbench.js b/tests/microbench.js
index 6bf0b83..b70e3fb 100644
--- a/tests/microbench.js
+++ b/tests/microbench.js
@@ -23,6 +23,10 @@
* THE SOFTWARE.
*/
+if (typeof require !== 'undefined') {
+ var fs = require('fs');
+}
+
function pad(str, n) {
str += "";
while (str.length < n)
@@ -63,9 +67,9 @@ function toPrec(n, prec) {
var ref_data;
var log_data;
-var heads = [ "TEST", "N", "TIME (ns)", "REF (ns)", "SCORE (%)" ];
+var heads = [ "TEST", "N", "TIME (ns)", "REF (ns)", "SCORE (1000)" ];
var widths = [ 22, 10, 9, 9, 9 ];
-var precs = [ 0, 0, 2, 2, 2 ];
+var precs = [ 0, 0, 2, 2, 0 ];
var total = [ 0, 0, 0, 0, 0 ];
var total_score = 0;
var total_scale = 0;
@@ -89,13 +93,27 @@ function log_line() {
}
var clocks_per_sec = 1000;
-var max_iterations = 10;
-var clock_threshold = 100; /* favoring short measuring spans */
+var max_iterations = 100;
+var clock_threshold = 2; /* favoring short measuring spans */
var min_n_argument = 1;
-var get_clock = Date.now;
-if (typeof(os) !== "undefined") {
+var get_clock;
+if (typeof performance !== "undefined") {
+ // use more precise clock on NodeJS
+ // need a method call on performance object
+ get_clock = () => performance.now();
+} else
+if (typeof os !== "undefined") {
// use more precise clock on QuickJS
get_clock = os.now;
+} else {
+ // use Date.now and round up to the next millisecond
+ get_clock = () => {
+ var t0 = Date.now();
+ var t;
+ while ((t = Date.now()) == t0)
+ continue;
+ return t;
+ }
}
function log_one(text, n, ti) {
@@ -109,7 +127,7 @@ function log_one(text, n, ti) {
ti = Math.round(ti * 100) / 100;
log_data[text] = ti;
if (typeof ref === "number") {
- log_line(text, n, ti, ref, ti * 100 / ref);
+ log_line(text, n, ti, ref, Math.round(ref * 1000 / ti));
total_score += ti * 100 / ref;
total_scale += 100;
} else {
@@ -121,28 +139,27 @@ function log_one(text, n, ti) {
function bench(f, text)
{
- var i, j, n, t, t1, ti, nb_its, ref, ti_n, ti_n1, min_ti;
+ var i, j, n, t, ti, nb_its, ref, ti_n, ti_n1;
nb_its = n = 1;
if (f.bench) {
ti_n = f(text);
} else {
+ // measure ti_n: the shortest time for an individual operation
ti_n = 1000000000;
- min_ti = clock_threshold / 10;
for(i = 0; i < 30; i++) {
+ // measure ti: the shortest time for max_iterations iterations
ti = 1000000000;
for (j = 0; j < max_iterations; j++) {
t = get_clock();
- while ((t1 = get_clock()) == t)
- continue;
nb_its = f(n);
+ t = get_clock() - t;
if (nb_its < 0)
return; // test failure
- t1 = get_clock() - t1;
- if (ti > t1)
- ti = t1;
+ if (ti > t)
+ ti = t;
}
- if (ti >= min_ti) {
+ if (ti >= clock_threshold / 10) {
ti_n1 = ti / nb_its;
if (ti_n > ti_n1)
ti_n = ti_n1;
@@ -196,6 +213,32 @@ function date_now(n) {
return n;
}
+function date_parse(n) {
+ var x0 = 0, dx = 0;
+ var j;
+ for(j = 0; j < n; j++) {
+ var x1 = x0 - x0 % 1000;
+ var x2 = -x0;
+ var x3 = -x1;
+ var d0 = new Date(x0);
+ var d1 = new Date(x1);
+ var d2 = new Date(x2);
+ var d3 = new Date(x3);
+ if (Date.parse(d0.toISOString()) != x0
+ || Date.parse(d1.toGMTString()) != x1
+ || Date.parse(d1.toString()) != x1
+ || Date.parse(d2.toISOString()) != x2
+ || Date.parse(d3.toGMTString()) != x3
+ || Date.parse(d3.toString()) != x3) {
+ console.log("Date.parse error for " + x0);
+ return -1;
+ }
+ dx = (dx * 1.1 + 1) >> 0;
+ x0 = (x0 + dx) % 8.64e15;
+ }
+ return n * 6;
+}
+
function prop_read(n)
{
var obj, sum, j;
@@ -224,30 +267,78 @@ function prop_write(n)
return n * 4;
}
-function prop_create(n)
+function prop_update(n)
{
var obj, j;
+ obj = {a: 1, b: 2, c:3, d:4 };
+ for(j = 0; j < n; j++) {
+ obj.a += j;
+ obj.b += j;
+ obj.c += j;
+ obj.d += j;
+ }
+ return n * 4;
+}
+
+function prop_create(n)
+{
+ var obj, i, j;
for(j = 0; j < n; j++) {
- obj = new Object();
+ obj = {};
obj.a = 1;
obj.b = 2;
obj.c = 3;
obj.d = 4;
+ obj.e = 5;
+ obj.f = 6;
+ obj.g = 7;
+ obj.h = 8;
+ obj.i = 9;
+ obj.j = 10;
+ for(i = 0; i < 10; i++) {
+ obj[i] = i;
+ }
}
- return n * 4;
+ return n * 20;
}
-function prop_delete(n)
+function prop_clone(n)
{
- var obj, j;
- obj = {};
- for(j = 0; j < n; j++) {
- obj[j] = 1;
+ var ref, obj, j, k;
+ ref = { a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10 };
+ for(k = 0; k < 10; k++) {
+ ref[k] = k;
}
- for(j = 0; j < n; j++) {
- delete obj[j];
+ for (j = 0; j < n; j++) {
+ global_res = { ...ref };
}
- return n;
+ return n * 20;
+}
+
+function prop_delete(n)
+{
+ var ref, obj, j, k;
+ ref = { a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10 };
+ for(k = 0; k < 10; k++) {
+ ref[k] = k;
+ }
+ for (j = 0; j < n; j++) {
+ obj = { ...ref };
+ delete obj.a;
+ delete obj.b;
+ delete obj.c;
+ delete obj.d;
+ delete obj.e;
+ delete obj.f;
+ delete obj.g;
+ delete obj.h;
+ delete obj.i;
+ delete obj.j;
+ for(k = 0; k < 10; k++) {
+ delete obj[k];
+ }
+ }
+ return n * 20;
}
function array_read(n)
@@ -308,15 +399,32 @@ function array_prop_create(n)
return len * n;
}
+function array_slice(n)
+{
+ var ref, a, i, j, len;
+ len = 1000;
+ ref = [];
+ for(i = 0; i < len; i++)
+ ref[i] = i;
+ for(j = 0; j < n; j++) {
+ ref[0] = j;
+ a = ref.slice();
+ a[0] = 0;
+ global_res = a;
+ }
+ return len * n;
+}
+
function array_length_decr(n)
{
- var tab, i, j, len;
+ var tab, ref, i, j, len;
len = 1000;
- tab = [];
+ ref = [];
for(i = 0; i < len; i++)
- tab[i] = i;
+ ref[i] = i;
for(j = 0; j < n; j++) {
- for(i = len - 1; i >= 0; i--)
+ tab = ref.slice();
+ for(i = len; i --> 0;)
tab.length = i;
}
return len * n;
@@ -324,15 +432,16 @@ function array_length_decr(n)
function array_hole_length_decr(n)
{
- var tab, i, j, len;
+ var tab, ref, i, j, len;
len = 1000;
- tab = [];
+ ref = [];
for(i = 0; i < len; i++) {
- if (i != 3)
- tab[i] = i;
+ if (i % 10 == 9)
+ ref[i] = i;
}
for(j = 0; j < n; j++) {
- for(i = len - 1; i >= 0; i--)
+ tab = ref.slice();
+ for(i = len; i --> 0;)
tab.length = i;
}
return len * n;
@@ -352,12 +461,13 @@ function array_push(n)
function array_pop(n)
{
- var tab, i, j, len, sum;
+ var tab, ref, i, j, len, sum;
len = 500;
+ ref = [];
+ for(i = 0; i < len; i++)
+ ref[i] = i;
for(j = 0; j < n; j++) {
- tab = [];
- for(i = 0; i < len; i++)
- tab[i] = i;
+ tab = ref.slice();
sum = 0;
for(i = 0; i < len; i++)
sum += tab.pop();
@@ -429,6 +539,7 @@ function global_read(n)
return n * 4;
}
+// non strict version
var global_write =
(1, eval)(`(function global_write(n)
{
@@ -471,6 +582,7 @@ function local_destruct(n)
var global_v1, global_v2, global_v3, global_v4;
var global_a, global_b, global_c, global_d;
+// non strict version
var global_destruct =
(1, eval)(`(function global_destruct(n)
{
@@ -498,6 +610,25 @@ function global_destruct_strict(n)
return n * 8;
}
+function g(a)
+{
+ return 1;
+}
+
+function global_func_call(n)
+{
+ var j, sum;
+ sum = 0;
+ for(j = 0; j < n; j++) {
+ sum += g(j);
+ sum += g(j);
+ sum += g(j);
+ sum += g(j);
+ }
+ global_res = sum;
+ return n * 4;
+}
+
function func_call(n)
{
function f(a)
@@ -517,7 +648,7 @@ function func_call(n)
return n * 4;
}
-function closure_var(n)
+function func_closure_call(n)
{
function f(a)
{
@@ -622,8 +753,8 @@ function bigint256_arith(n)
function set_collection_add(n)
{
var s, i, j, len = 100;
- s = new Set();
for(j = 0; j < n; j++) {
+ s = new Set();
for(i = 0; i < len; i++) {
s.add(String(i), i);
}
@@ -637,25 +768,25 @@ function set_collection_add(n)
function array_for(n)
{
- var r, i, j, sum;
+ var r, i, j, sum, len = 100;
r = [];
- for(i = 0; i < 100; i++)
+ for(i = 0; i < len; i++)
r[i] = i;
for(j = 0; j < n; j++) {
sum = 0;
- for(i = 0; i < 100; i++) {
+ for(i = 0; i < len; i++) {
sum += r[i];
}
global_res = sum;
}
- return n * 100;
+ return n * len;
}
function array_for_in(n)
{
- var r, i, j, sum;
+ var r, i, j, sum, len = 100;
r = [];
- for(i = 0; i < 100; i++)
+ for(i = 0; i < len; i++)
r[i] = i;
for(j = 0; j < n; j++) {
sum = 0;
@@ -664,14 +795,14 @@ function array_for_in(n)
}
global_res = sum;
}
- return n * 100;
+ return n * len;
}
function array_for_of(n)
{
- var r, i, j, sum;
+ var r, i, j, sum, len = 100;
r = [];
- for(i = 0; i < 100; i++)
+ for(i = 0; i < len; i++)
r[i] = i;
for(j = 0; j < n; j++) {
sum = 0;
@@ -680,7 +811,7 @@ function array_for_of(n)
}
global_res = sum;
}
- return n * 100;
+ return n * len;
}
function math_min(n)
@@ -700,11 +831,11 @@ function regexp_ascii(n)
var i, j, r, s;
s = "the quick brown fox jumped over the lazy dog"
for(j = 0; j < n; j++) {
- for(i = 0; i < 10000; i++)
+ for(i = 0; i < 1000; i++)
r = /the quick brown fox/.exec(s)
global_res = r;
}
- return n * 10000;
+ return n * 1000;
}
function regexp_utf16(n)
@@ -712,91 +843,91 @@ function regexp_utf16(n)
var i, j, r, s;
s = "the quick brown ᶠᵒˣ jumped over the lazy ᵈᵒᵍ"
for(j = 0; j < n; j++) {
- for(i = 0; i < 10000; i++)
+ for(i = 0; i < 1000; i++)
r = /the quick brown ᶠᵒˣ/.exec(s)
global_res = r;
}
- return n * 10000;
+ return n * 1000;
}
/* incremental string contruction as local var */
function string_build1(n)
{
var i, j, r;
- r = "";
for(j = 0; j < n; j++) {
- for(i = 0; i < 100; i++)
+ r = "";
+ for(i = 0; i < 1000; i++)
r += "x";
global_res = r;
}
- return n * 100;
+ return n * 1000;
}
/* incremental string contruction using + */
function string_build1x(n)
{
var i, j, r;
- r = "";
for(j = 0; j < n; j++) {
- for(i = 0; i < 100; i++)
+ r = "";
+ for(i = 0; i < 1000; i++)
r = r + "x";
global_res = r;
}
- return n * 100;
+ return n * 1000;
}
/* incremental string contruction using +2c */
function string_build2c(n)
{
var i, j;
- var r = "";
for(j = 0; j < n; j++) {
- for(i = 0; i < 100; i++)
+ var r = "";
+ for(i = 0; i < 1000; i++)
r += "xy";
global_res = r;
}
- return n * 100;
+ return n * 1000;
}
/* incremental string contruction as arg */
function string_build2(n, r)
{
var i, j;
- r = "";
for(j = 0; j < n; j++) {
- for(i = 0; i < 100; i++)
+ r = "";
+ for(i = 0; i < 1000; i++)
r += "x";
global_res = r;
}
- return n * 100;
+ return n * 1000;
}
/* incremental string contruction by prepending */
function string_build3(n)
{
var i, j, r;
- r = "";
for(j = 0; j < n; j++) {
- for(i = 0; i < 100; i++)
+ r = "";
+ for(i = 0; i < 1000; i++)
r = "x" + r;
global_res = r;
}
- return n * 100;
+ return n * 1000;
}
/* incremental string contruction with multiple reference */
function string_build4(n)
{
var i, j, r, s;
- r = "";
for(j = 0; j < n; j++) {
- for(i = 0; i < 100; i++) {
+ r = "";
+ for(i = 0; i < 1000; i++) {
s = r;
r += "x";
}
global_res = r;
}
- return n * 100;
+ return n * 1000;
}
/* sort bench */
@@ -940,21 +1071,22 @@ sort_bench.verbose = false;
function int_to_string(n)
{
- var s, r, j;
- r = 0;
+ var s, j;
for(j = 0; j < n; j++) {
- s = (j + 1).toString();
+ s = (j % 1000).toString();
+ s = (1234000 + j % 1000).toString();
}
- return n;
+ global_res = s;
+ return n * 2;
}
function float_to_string(n)
{
- var s, r, j;
- r = 0;
+ var s, j;
for(j = 0; j < n; j++) {
s = (j + 0.1).toString();
}
+ global_res = s;
return n;
}
@@ -963,7 +1095,6 @@ function string_to_int(n)
var s, r, j;
r = 0;
s = "12345";
- r = 0;
for(j = 0; j < n; j++) {
r += (s | 0);
}
@@ -976,7 +1107,6 @@ function string_to_float(n)
var s, r, j;
r = 0;
s = "12345.6";
- r = 0;
for(j = 0; j < n; j++) {
r -= s;
}
@@ -986,32 +1116,70 @@ function string_to_float(n)
function load_result(filename)
{
- var f, str, res;
- if (typeof std === "undefined")
+ var has_filename = filename;
+ var has_error = false;
+ var str, res;
+
+ if (!filename)
+ filename = "microbench.txt";
+
+ if (typeof fs !== "undefined") {
+ // read the file in Node.js
+ try {
+ str = fs.readFileSync(filename, { encoding: "utf8" });
+ } catch {
+ has_error = true;
+ }
+ } else
+ if (typeof std !== "undefined") {
+ // read the file in QuickJS
+ var f = std.open(filename, "r");
+ if (!f) {
+ has_error = true;
+ }
+ str = f.readAsString();
+ f.close();
+ } else {
return null;
- f = std.open(filename ? filename : "microbench.txt", "r");
- if (!f) {
- if (filename) {
+ }
+ if (has_error) {
+ if (has_filename) {
// Should throw exception?
console.log("cannot load " + filename);
}
return null;
}
- str = f.readAsString();
res = JSON.parse(str);
- f.close();
return res;
}
function save_result(filename, obj)
{
- var f;
- if (typeof std === "undefined")
+ var str = JSON.stringify(obj, null, 2) + "\n";
+ var has_error = false;
+
+ if (typeof fs !== "undefined") {
+ // save the file in Node.js
+ try {
+ str = fs.writeFileSync(filename, str, { encoding: "utf8" });
+ } catch {
+ has_error = true;
+ }
+ } else
+ if (typeof std !== "undefined") {
+ // save the file in QuickJS
+ var f = std.open(filename, "w");
+ if (f) {
+ f.puts(str);
+ f.close();
+ } else {
+ has_error = 'true';
+ }
+ } else {
return;
- f = std.open(filename, "w");
- f.puts(JSON.stringify(obj, null, 2));
- f.puts("\n");
- f.close();
+ }
+ if (has_error)
+ console.log("cannot save " + filename);
}
function main(argc, argv, g)
@@ -1022,13 +1190,17 @@ function main(argc, argv, g)
empty_down_loop2,
empty_do_loop,
date_now,
+ date_parse,
prop_read,
prop_write,
+ prop_update,
prop_create,
+ prop_clone,
prop_delete,
array_read,
array_write,
array_prop_create,
+ array_slice,
array_length_decr,
array_hole_length_decr,
array_push,
@@ -1041,8 +1213,9 @@ function main(argc, argv, g)
local_destruct,
global_destruct,
global_destruct_strict,
+ global_func_call,
func_call,
- closure_var,
+ func_closure_call,
int_arith,
float_arith,
set_collection_add,
@@ -1065,7 +1238,7 @@ function main(argc, argv, g)
];
var tests = [];
var i, j, n, f, name, found;
- var ref_file;
+ var ref_file, new_ref_file = "microbench-new.txt";
if (typeof BigInt === "function") {
/* BigInt test */
@@ -1101,6 +1274,10 @@ function main(argc, argv, g)
ref_file = argv[i++];
continue;
}
+ if (name == "-s") {
+ new_ref_file = argv[i++];
+ continue;
+ }
for (j = 0, found = false; j < test_list.length; j++) {
f = test_list[j];
if (f.name.startsWith(name)) {
@@ -1128,12 +1305,12 @@ function main(argc, argv, g)
n++;
}
if (ref_data)
- log_line("total", "", total[2], total[3], total_score * 100 / total_scale);
+ log_line("total", "", total[2], total[3], Math.round(total_scale * 1000 / total_score));
else
log_line("total", "", total[2]);
- if (tests == test_list)
- save_result("microbench-new.txt", log_data);
+ if (tests == test_list && new_ref_file)
+ save_result(new_ref_file, log_data);
}
if (typeof scriptArgs === "undefined") {