• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the 'License');
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an 'AS IS' BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16const {
17    MODULE_PATH,
18    ARK_ETS_STDLIB_PATH,
19    ARK_ETS_INTEROP_JS_GTEST_ABC_PATH,
20    VMB_BENCH_UNIT_NAME,
21    VMB_BENCH_UNIT_ITERATIONS
22} = process.env;
23
24const DEFAULT_ITERATIONS = 100000;
25
26globalThis.require = require;
27
28const capitalize = (str = '') => {
29    return str.split('_')
30        .filter(Boolean)
31        .map((substring, i) =>
32            substring[0].toUpperCase() + substring.substring(1))
33        .join('');
34};
35
36class Benchmark {
37    #ark = require(MODULE_PATH + '/ets_interop_js_napi.node');
38    #benchName = capitalize(VMB_BENCH_UNIT_NAME);
39    #benchmark;
40    #passedTime = BigInt(0);
41    #binaries = [];
42    constructor(...binaries) {
43        this.#binaries = binaries;
44        this.#__init();
45    }
46
47    #__init() {
48        const isOk = this.#ark.createRuntime({
49            'boot-panda-files': [ARK_ETS_STDLIB_PATH, ...this.#binaries].join(':'),
50            'panda-files': this.#binaries.join(':'),
51            'gc-trigger-type': 'heap-trigger',
52            'compiler-enable-jit': 'false',
53            'run-gc-in-place': 'true',
54            'log-components': 'ets_interop_js',
55            'load-runtimes': 'ets'
56        });
57
58        if (!isOk) {
59            throw new Error('Failed to initialize');
60        }
61    }
62
63    #prepare() {
64        const TestClass = this.#ark.getClass(`L${this.#benchName};`);
65        this.#benchmark = new TestClass();
66        this.#benchmark.setup();
67    }
68
69    #loopFromJS(iterations = DEFAULT_ITERATIONS) {
70        if (!Number.isFinite(iterations)) {
71            throw new Error(`Iteration count should be a valid integer, ${iterations} given instead`);
72        }
73        for (let i = 0; i < iterations ?? this.iterations; i++) {
74            const startTimeNsec = process.hrtime.bigint();
75            this.#benchmark.test();
76            const endTimeNSec = process.hrtime.bigint();
77            this.#passedTime += (endTimeNSec - startTimeNsec);
78        }
79        return this.#passedTime;
80    }
81
82    #loopFromArk(iterations = DEFAULT_ITERATIONS) {
83        if (!Number.isFinite(iterations)) {
84            throw new Error(`Iteration count should be a valid integer, ${iterations} given instead`);
85        }
86        this.#benchmark.runsLeft = iterations;
87        return Number(this.#benchmark.test());
88    }
89
90    run(iterations = DEFAULT_ITERATIONS) {
91        this.#prepare();
92        const isSelfTimed = this.#benchmark.totalTime !== undefined;
93        const testRunner = isSelfTimed ? this.#loopFromArk.bind(this) : this.#loopFromJS.bind(this);
94        const timing = testRunner(iterations);
95        console.log(`Benchmark result: ${this.#benchName.toLowerCase()} ` + timing);
96    }
97}
98
99const benchmark = new Benchmark(ARK_ETS_INTEROP_JS_GTEST_ABC_PATH);
100
101const iterations = (VMB_BENCH_UNIT_ITERATIONS && Number.isFinite(Number(VMB_BENCH_UNIT_ITERATIONS)))
102    ? Number(VMB_BENCH_UNIT_ITERATIONS)
103    : DEFAULT_ITERATIONS;
104
105benchmark.run(iterations);