diff --git a/etherlink/kernel_evm/benchmarks/package-lock.json b/etherlink/kernel_evm/benchmarks/package-lock.json index 193fdacdb2791c17e2079a2686d836f6cb7552ef..d905dfb4a51ca85efb31859413740d5c4e38cb9c 100644 --- a/etherlink/kernel_evm/benchmarks/package-lock.json +++ b/etherlink/kernel_evm/benchmarks/package-lock.json @@ -17,6 +17,7 @@ "ethereumjs-wallet": "^1.0.2", "ethers": "^6.7.1", "keccak": "^3.0.3", + "ml-regression-multivariate-linear": "^2.0.4", "rlp": "^2.2.7", "solc": "^0.8.21" }, @@ -705,6 +706,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/is-any-array": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-any-array/-/is-any-array-2.0.1.tgz", + "integrity": "sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==" + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -867,6 +873,49 @@ "node": ">=10" } }, + "node_modules/ml-array-max": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/ml-array-max/-/ml-array-max-1.2.4.tgz", + "integrity": "sha512-BlEeg80jI0tW6WaPyGxf5Sa4sqvcyY6lbSn5Vcv44lp1I2GR6AWojfUvLnGTNsIXrZ8uqWmo8VcG1WpkI2ONMQ==", + "dependencies": { + "is-any-array": "^2.0.0" + } + }, + "node_modules/ml-array-min": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/ml-array-min/-/ml-array-min-1.2.3.tgz", + "integrity": "sha512-VcZ5f3VZ1iihtrGvgfh/q0XlMobG6GQ8FsNyQXD3T+IlstDv85g8kfV0xUG1QPRO/t21aukaJowDzMTc7j5V6Q==", + "dependencies": { + "is-any-array": "^2.0.0" + } + }, + "node_modules/ml-array-rescale": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ml-array-rescale/-/ml-array-rescale-1.3.7.tgz", + "integrity": "sha512-48NGChTouvEo9KBctDfHC3udWnQKNKEWN0ziELvY3KG25GR5cA8K8wNVzracsqSW1QEkAXjTNx+ycgAv06/1mQ==", + "dependencies": { + "is-any-array": "^2.0.0", + "ml-array-max": "^1.2.4", + "ml-array-min": "^1.2.3" + } + }, + "node_modules/ml-matrix": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/ml-matrix/-/ml-matrix-6.11.0.tgz", + "integrity": "sha512-7jr9NmFRkaUxbKslfRu3aZOjJd2LkSitCGv+QH9PF0eJoEG7jIpjXra1Vw8/kgao8+kHCSsJONG6vfWmXQ+/Eg==", + "dependencies": { + "is-any-array": "^2.0.1", + "ml-array-rescale": "^1.3.7" + } + }, + "node_modules/ml-regression-multivariate-linear": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/ml-regression-multivariate-linear/-/ml-regression-multivariate-linear-2.0.4.tgz", + "integrity": "sha512-/vShPAlP+mB7P2mC5TuXwObSJNl/UBI71/bszt9ilTg6yLKy6btDLpAYyJNa6t+JnL5a7q+Yy4dCltfpvqXRIw==", + "dependencies": { + "ml-matrix": "^6.10.1" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -1910,6 +1959,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "is-any-array": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-any-array/-/is-any-array-2.0.1.tgz", + "integrity": "sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==" + }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -2030,6 +2084,49 @@ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "optional": true }, + "ml-array-max": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/ml-array-max/-/ml-array-max-1.2.4.tgz", + "integrity": "sha512-BlEeg80jI0tW6WaPyGxf5Sa4sqvcyY6lbSn5Vcv44lp1I2GR6AWojfUvLnGTNsIXrZ8uqWmo8VcG1WpkI2ONMQ==", + "requires": { + "is-any-array": "^2.0.0" + } + }, + "ml-array-min": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/ml-array-min/-/ml-array-min-1.2.3.tgz", + "integrity": "sha512-VcZ5f3VZ1iihtrGvgfh/q0XlMobG6GQ8FsNyQXD3T+IlstDv85g8kfV0xUG1QPRO/t21aukaJowDzMTc7j5V6Q==", + "requires": { + "is-any-array": "^2.0.0" + } + }, + "ml-array-rescale": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ml-array-rescale/-/ml-array-rescale-1.3.7.tgz", + "integrity": "sha512-48NGChTouvEo9KBctDfHC3udWnQKNKEWN0ziELvY3KG25GR5cA8K8wNVzracsqSW1QEkAXjTNx+ycgAv06/1mQ==", + "requires": { + "is-any-array": "^2.0.0", + "ml-array-max": "^1.2.4", + "ml-array-min": "^1.2.3" + } + }, + "ml-matrix": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/ml-matrix/-/ml-matrix-6.11.0.tgz", + "integrity": "sha512-7jr9NmFRkaUxbKslfRu3aZOjJd2LkSitCGv+QH9PF0eJoEG7jIpjXra1Vw8/kgao8+kHCSsJONG6vfWmXQ+/Eg==", + "requires": { + "is-any-array": "^2.0.1", + "ml-array-rescale": "^1.3.7" + } + }, + "ml-regression-multivariate-linear": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/ml-regression-multivariate-linear/-/ml-regression-multivariate-linear-2.0.4.tgz", + "integrity": "sha512-/vShPAlP+mB7P2mC5TuXwObSJNl/UBI71/bszt9ilTg6yLKy6btDLpAYyJNa6t+JnL5a7q+Yy4dCltfpvqXRIw==", + "requires": { + "ml-matrix": "^6.10.1" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", diff --git a/etherlink/kernel_evm/benchmarks/package.json b/etherlink/kernel_evm/benchmarks/package.json index f9d4f875021c02dd5932493eb0a3e7f3d1bcd6cc..1d1b6e6c00a0436ee13ec93d2a9b91134f88e034 100644 --- a/etherlink/kernel_evm/benchmarks/package.json +++ b/etherlink/kernel_evm/benchmarks/package.json @@ -12,7 +12,8 @@ "solc": "^0.8.21", "csv-parse": "5.5.0", "csv-stringify": "^6.4.2", - "commander": "^11.0.0" + "commander": "^11.0.0", + "ml-regression-multivariate-linear": "^2.0.4" }, "optionalDependencies": { "chartjs-node-canvas": "^4.1.6", diff --git a/etherlink/kernel_evm/benchmarks/scripts/analysis/analysis.js b/etherlink/kernel_evm/benchmarks/scripts/analysis/analysis.js index 1f43ac726a5883bc938f9efd6bd06fb11ad81e57..df4847adcd96f773122868b4852153b71bba7271 100644 --- a/etherlink/kernel_evm/benchmarks/scripts/analysis/analysis.js +++ b/etherlink/kernel_evm/benchmarks/scripts/analysis/analysis.js @@ -2,14 +2,16 @@ // // SPDX-License-Identifier: MIT -const { ChartJSNodeCanvas } = require('chartjs-node-canvas'); const { is_transfer, is_create, is_transaction, BASE_GAS } = require('./utils') -// const { ChartConfiguration } = require('chart') -const fs = require('fs'); +const fs = require('fs') +const fetch = require('./fetch') +const block_finalization = require('./block_finalization') +const tx_register = require('./tx_register') +const tx_overhead = require('./tx_overhead') +const queue = require('./queue') const number_formatter_compact = Intl.NumberFormat('en', { notation: 'compact', compactDisplay: 'long' }); const number_formatter = Intl.NumberFormat('en', {}); -const RUN_TRANSACTION_OVERHEAD = 560_000 module.exports = { init_analysis, check_result, process_record } @@ -18,40 +20,67 @@ function init_analysis() { // total amount of gas consumed total_gas: 0, // total amount of ticks used in run_transaction_ticks - total_ticks_tx: 0, - tick_per_gas: [], - run_transaction_overhead: [], + sputnik_ticks: 0, + pure_transfers_ticks: [], init: 0, decode: 0, signatures: [], nb_kernel_run: 0, nb_call: 0, - nb_create: 0, nb_transfer: 0, - kernel_runs: [] + kernel_runs: [], + fetch_data: [], + block_finalization: [], + tx_register: [], + tx_overhead: [], + runs_infos: [] }; return empty } function print_analysis(infos) { - const tickPerGas = infos.total_ticks_tx / infos.total_gas + console.info(`-------------------------------------------------------`) + console.info(`Fetch Analysis`) + console.info(`----------------------------------`) + let error_fetch = fetch.print_fetch_analysis(infos) + console.info(`-------------------------------------------------------`) + console.info(`Block Finalization Analysis`) + console.info(`----------------------------------`) + let error_block_finalization = block_finalization.print_analysis(infos) + console.info(`-------------------------------------------------------`) + console.info(`Queue read and storage analysis`) + console.info(`----------------------------------`) + let error_queue = queue.print_analysis(infos) + console.info(`-------------------------------------------------------`) + console.info(`Transaction Registering Analysis`) + console.info(`----------------------------------`) + let error_register = tx_register.print_analysis(infos) + console.info(`-------------------------------------------------------`) + console.info(`Transaction Overhead Analysis`) + console.info(`----------------------------------`) + // model is known to fall short as an overapproximation + let _error_tx_overhead = tx_overhead.print_analysis(infos) console.info(`-------------------------------------------------------`) console.info(`Kernels infos`) - console.info(`Overall tick per gas: ~${tickPerGas.toFixed()}`) - console.info(`Tick per gas: ${pp_avg_max(infos.tick_per_gas)}`) - console.info(`Signature verification: ${pp_avg_max(infos.signatures)}`) + console.info(`----------------------------------`) console.info(`Decoding: ${pp(infos.decode)} ticks`) console.info(`Initialisation: ${pp(infos.init)} ticks`) - console.info(`transfer overhead: ${pp_avg_max(infos.run_transaction_overhead)} `) + console.info(`Signature verification: ${pp_avg_max(infos.signatures.filter((x) => !!x))}`) + console.info(`Transfer tick cost: ${pp_avg_max(infos.pure_transfers_ticks.filter((x) => !!x))} `) console.info(`-------------------------------------------------------`) - console.info(`Benchmark run infos`) + console.info(`Benchmark run stats`) + console.info(`----------------------------------`) + console.info(`Total gas in execution: ${pp(infos.total_gas)}`) + console.info(`Total ticks in sputnik: ${pp(infos.sputnik_ticks)}`) console.info(`Number of tx: ${infos.signatures.length}`) console.info(`Number of kernel run: ${infos.nb_kernel_run}`) console.info(`Number of transfers: ${infos.nb_transfer}`) - console.info(`Number of create: ${infos.nb_create}`) - console.info(`Number of call: ${infos.nb_call}`) + console.info(`Number of create/call: ${infos.nb_call}`) + console.info(`Number of kernel run: ${infos.nb_kernel_run}`) + console.info(`Number of blocks: ${infos.block_finalization.length}`) console.info(`-------------------------------------------------------`) + return error_fetch + error_block_finalization + error_register + error_queue } @@ -61,45 +90,78 @@ function process_record(record, acc) { } function process_bench_record(record, acc) { - if (!isNaN(record.interpreter_decode_ticks)) acc.init = record.interpreter_decode_ticks - if (!isNaN(record.interpreter_init_ticks)) acc.decode = record.interpreter_init_ticks - if (!isNaN(record.interpreter_decode_ticks)) acc.nb_kernel_run += 1 + acc.runs_infos.push(record) + if (!isNaN(record.interpreter_decode_ticks)) { + acc.nb_kernel_run += 1 + acc.decode = Math.max(acc.decode, record.interpreter_decode_ticks) + acc.init = Math.max(acc.init, record.interpreter_init_ticks) + } if (!isNaN(record.kernel_run_ticks)) acc.kernel_runs.push(record.kernel_run_ticks) + + // Adds info needed for fetch analysis + if (!isNaN(record.fetch_blueprint_ticks) && !isNaN(record.nb_tx)) { + acc.fetch_data.push({ + ticks: record.fetch_blueprint_ticks, + size: record.inbox_size, + nb_tx: record.nb_tx, + benchmark_name: record.benchmark_name + }) + } + + // Adds infos needed for block finalization analysis + if (!isNaN(record.inbox_size)) { + acc.block_finalization.push(record) + } + if (!isNaN(record.block_finalize)) { + // add block_finalize info to last record if same benchmark + let last_record = acc.block_finalization.pop() + if (last_record.benchmark_name == record.benchmark_name) { + last_record.block_finalize = record.block_finalize + acc.block_finalization.push(last_record) + } else { + console.error("[Error] couldn't find correct finalize information") + } + } } function process_transaction_record(record, acc) { acc.signatures.push(record.signature_verification_ticks) if (is_transfer(record)) process_transfer(record, acc) - else if (is_create(record)) process_create(record, acc) - else process_call(record, acc) + else process_execution(record, acc) + + // Adds infos for tx registration analysis + if (!isNaN(record.tx_size) && !isNaN(record.store_transaction_object_ticks)) + acc.tx_register.push(record) + + // Adds infos for transaction overhead analysis + if (!isNaN(record.tx_size) && !isNaN(record.sputnik_runtime_ticks) && !isNaN(record.run_transaction_ticks)) + acc.tx_overhead.push(record) } function process_transfer(record, acc) { - acc.run_transaction_overhead.push(record.run_transaction_ticks) + acc.pure_transfers_ticks.push(record.run_transaction_ticks) acc.nb_transfer++ } -function process_create(record, acc) { - acc.nb_create++ - -} -function process_call(record, acc) { +function process_execution(record, acc) { acc.nb_call++ let gas = record.gas_cost - BASE_GAS - let ticks = record.run_transaction_ticks - RUN_TRANSACTION_OVERHEAD - acc.total_gas += gas - acc.total_ticks_tx += ticks - acc.tick_per_gas.push(ticks / gas) + if (!isNaN(record.gas_cost)) acc.total_gas += gas + if (!isNaN(record.sputnik_runtime_ticks)) acc.sputnik_ticks += record.sputnik_runtime_ticks } function check_result(infos) { - const tickPerGas = infos.total_ticks_tx / infos.total_gas - print_analysis(infos) - const is_error = tickPerGas > 2000 + const tickPerGas = infos.sputnik_ticks / infos.total_gas + let nb_errors = print_analysis(infos) + const is_error = nb_errors > 0 if (is_error) { - console.error(`Tick per gas too high!`) + console.info(`-------------------------------------------------------`) + console.error(`WARNING: too many model underestimation (${nb_errors})`) + console.info(`-------------------------------------------------------`) return 1 + } else { + console.log(`Global tpg: ${tickPerGas}`) } return 0 } diff --git a/etherlink/kernel_evm/benchmarks/scripts/analysis/block_finalization.js b/etherlink/kernel_evm/benchmarks/scripts/analysis/block_finalization.js new file mode 100644 index 0000000000000000000000000000000000000000..fa93e67a54085cf4b8e8e12f7c5428ff35a82569 --- /dev/null +++ b/etherlink/kernel_evm/benchmarks/scripts/analysis/block_finalization.js @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2023 Marigold +// +// SPDX-License-Identifier: MIT + +const path = require('node:path') +module.exports = { print_analysis } +const utils = require("./utils") +const OUTPUT = 'block_finalization_data.csv' +const UPPER_BOUND = 125000000 + +function print_analysis(infos, dir = "analysis_result") { + let mlr = utils.make_lr(infos.block_finalization, (x) => x.nb_tx, (y) => y.block_finalize) + console.log(`Linear Regression: ${utils.print_lr(mlr, "nbtx")} `) + + utils.print_csv(dir, OUTPUT, infos.block_finalization, ["benchmark_name", "inbox_size", "nb_tx", "block_finalize"]) + + console.log(`current model: Y = ${UPPER_BOUND} `) + return utils.print_summary_errors(infos.block_finalization, datum => { return datum.block_finalize - UPPER_BOUND }) +} diff --git a/etherlink/kernel_evm/benchmarks/scripts/analysis/fetch.js b/etherlink/kernel_evm/benchmarks/scripts/analysis/fetch.js new file mode 100644 index 0000000000000000000000000000000000000000..18d10a6c3aba6ab1992a18c5516bb88f7f103476 --- /dev/null +++ b/etherlink/kernel_evm/benchmarks/scripts/analysis/fetch.js @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2023 Marigold +// +// SPDX-License-Identifier: MIT + +const path = require('node:path') +module.exports = { print_fetch_analysis } +const utils = require("./utils") +const OUTPUT = 'fetch_data.csv' +const UPPER_BOUND = 1_000_000_000 + +function print_fetch_analysis(infos, dir = "analysis_result") { + // prepare data + + utils.print_csv(dir, OUTPUT, infos.fetch_data, ["benchmark_name", "size", "nb_tx", "ticks"]) + + // compute errors + console.log(`current model: Y = ${UPPER_BOUND}`) + return utils.print_summary_errors(infos.fetch_data, datum => { return datum.ticks - UPPER_BOUND }) +} diff --git a/etherlink/kernel_evm/benchmarks/scripts/analysis/queue.js b/etherlink/kernel_evm/benchmarks/scripts/analysis/queue.js new file mode 100644 index 0000000000000000000000000000000000000000..d33db6490b5c134c836a9c39b4d61823b3bc782f --- /dev/null +++ b/etherlink/kernel_evm/benchmarks/scripts/analysis/queue.js @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2023 Marigold +// +// SPDX-License-Identifier: MIT + +const path = require('node:path') +module.exports = { print_analysis } +const utils = require("./utils") +const OUTPUT_STORE = 'queue_storing_data.csv' +const OUTPUT_READ = 'queue_reading_data.csv' +const READ_UPPER_BOUND = 500_000_000 +const STORE_UPPER_BOUND = 1_100_000_000 + +function print_analysis(infos, dir = "analysis_result") { + const read_data = infos.runs_infos.filter((d) => !!d.queue_read); + let mlr_read = utils.make_lr(read_data, (x) => x.queue_read, (y) => y.queue_read_ticks) + console.log(`[read] Computed LR: ${utils.print_lr(mlr_read)} `) + let error_read = utils.print_summary_errors(read_data, datum => { return datum.queue_read_ticks - READ_UPPER_BOUND }, "[read]") + + utils.print_csv(dir, OUTPUT_READ, read_data, ["benchmark_name", "queue_read", "queue_read_ticks"]) + + const store_data = infos.runs_infos.filter((d) => !!d.queue_store); + let mlr_store = utils.make_lr(store_data, (x) => x.queue_store, (y) => y.queue_store_ticks) + console.log(`[store] Computed LR: ${utils.print_lr(mlr_store)} `) + let error_store = utils.print_summary_errors(store_data, datum => { return datum.queue_store_ticks - STORE_UPPER_BOUND }, "[store]") + + utils.print_csv(dir, OUTPUT_STORE, store_data, ["benchmark_name", "queue_store", "queue_store_ticks"]) + + return error_read + error_store; +} \ No newline at end of file diff --git a/etherlink/kernel_evm/benchmarks/scripts/analysis/tx_overhead.js b/etherlink/kernel_evm/benchmarks/scripts/analysis/tx_overhead.js new file mode 100644 index 0000000000000000000000000000000000000000..37b18adc37a0bc3cfdb0efa65dfc9ee1dff091b4 --- /dev/null +++ b/etherlink/kernel_evm/benchmarks/scripts/analysis/tx_overhead.js @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2023 Marigold +// +// SPDX-License-Identifier: MIT + +const path = require('node:path') +module.exports = { print_analysis } +const utils = require("./utils") +const OUTPUT = 'tx_overhead_data.csv' +const MODEL = { intercept: 1_150_000, coef: 880 } + +function print_analysis(infos, dir = "analysis_result") { + const data = infos.tx_overhead; + for (datum of data) { + datum.tx_overhead = datum.run_transaction_ticks - datum.sputnik_runtime_ticks + } + console.log(`Current model: ${utils.print_model(MODEL, "tx_size")}`) + let lr = utils.make_lr(infos.tx_register, (x) => x.tx_size, (y) => y.tx_overhead) + console.log(`Computed LR: ${utils.print_lr(lr)} `) + let error = utils.print_summary_errors(infos.tx_register, datum => { return datum.tx_overhead - utils.predict_linear_model(MODEL, datum.tx_size) }) + + utils.print_csv(dir, OUTPUT, data, ["benchmark_name", "status", "gas_cost", "tx_size", "run_transaction_ticks", "sputnik_runtime_ticks", "tx_overhead"]) + + return error +} \ No newline at end of file diff --git a/etherlink/kernel_evm/benchmarks/scripts/analysis/tx_register.js b/etherlink/kernel_evm/benchmarks/scripts/analysis/tx_register.js new file mode 100644 index 0000000000000000000000000000000000000000..942e1753b01935f7201caa2da73c0b808837efba --- /dev/null +++ b/etherlink/kernel_evm/benchmarks/scripts/analysis/tx_register.js @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2023 Marigold +// +// SPDX-License-Identifier: MIT + +const path = require('node:path') +module.exports = { print_analysis } +const utils = require("./utils") +const OUTPUT = 'register_tx_data.csv' +const MODEL_OBJ = { intercept: 200000, coef: 880 } +const MODEL_RECEIPT = { intercept: 200000, coef: 960 } +const MODEL_LOGBLOOM = { intercept: 5300, coef: 85000 } + +function print_analysis(infos, dir = "analysis_result") { + + function print_csv(name, columns) { + utils.print_csv(dir, name + OUTPUT, infos.tx_register, columns) + } + + // transaction object + console.log(`[object] Current model: ${utils.print_model(MODEL_OBJ, "size")}`) + let obj_lr = utils.make_lr(infos.tx_register, (x) => x.tx_size, (y) => y.store_transaction_object_ticks) + console.log(`[object] Computed LR: ${utils.print_lr(obj_lr)} `) + let error_object = utils.print_summary_errors(infos.tx_register, datum => { return datum.tx_size - utils.predict_linear_model(MODEL_OBJ, datum.receipt_size) }, "[object]") + + print_csv( + "object_", + ["benchmark_name", "tx_size", "store_transaction_object_ticks",] + ) + + // receipt + console.log(`[receipt] Current model: ${utils.print_model(MODEL_RECEIPT, "size")}`) + let receipt_lr = utils.make_lr(infos.tx_register, (x) => x.receipt_size, (y) => y.store_receipt_ticks) + console.log(`[receipt] Computed LR: ${utils.print_lr(receipt_lr)} `) + let error_receipt = utils.print_summary_errors(infos.tx_register, datum => { return datum.store_receipt_ticks - utils.predict_linear_model(MODEL_RECEIPT, datum.receipt_size) }, "[receipt]") + + print_csv( + "receipt_", + ["benchmark_name", "receipt_size", "store_receipt_ticks"] + ) + + // bloom + console.log(`[bloom] Current model: ${utils.print_model(MODEL_LOGBLOOM, "size")}`) + let bloom_lr = utils.make_lr(infos.tx_register, (x) => x.bloom_size, (y) => y.logs_to_bloom) + console.log(`[bloom] Computed LR: ${utils.print_lr(bloom_lr)} `) + let error_bloom = utils.print_summary_errors(infos.tx_register, datum => { return datum.logs_to_bloom - utils.predict_linear_model(MODEL_LOGBLOOM, datum.bloom_size) }, "[bloom]") + + print_csv( + "bloom_", + ["benchmark_name", "bloom_size", "logs_to_bloom"] + ) + + let errors = error_receipt + error_object + error_bloom + console.log(`Total errors: ${errors}`) + return errors +} diff --git a/etherlink/kernel_evm/benchmarks/scripts/analysis/utils.js b/etherlink/kernel_evm/benchmarks/scripts/analysis/utils.js index 288bfb3d58c422a8e0b0b7810755119bd91badc2..68d8e977e92468cc9fe17dc5e8f5966b1e481e08 100644 --- a/etherlink/kernel_evm/benchmarks/scripts/analysis/utils.js +++ b/etherlink/kernel_evm/benchmarks/scripts/analysis/utils.js @@ -5,8 +5,13 @@ const BASE_GAS = 21000 const CREATE_STORAGE_CUTOFF = 600_000 +const MLR = require("ml-regression-multivariate-linear") -module.exports = { is_transfer, is_create, is_transaction, BASE_GAS } +const path = require('node:path') +const fs = require('fs'); +const csv = require('csv-stringify/sync'); + +module.exports = { is_transfer, is_create, is_transaction, BASE_GAS, make_lr, print_lr, print_summary_errors, print_model, predict_linear_model, print_csv } function is_transfer(record) { return record.gas_cost == BASE_GAS @@ -17,4 +22,56 @@ function is_create(record) { function is_transaction(record) { return !record.benchmark_name.includes("(all)") +} + +function make_lr(data, select_x, select_y) { + + var X = [] + var Y = [] + for (datum of data) { + let x = select_x(datum) + let y = select_y(datum) + if (!!x && !!y) { + X.push([x]) + Y.push([y]) + } + } + if (X.length > 0) { + let mlr = new MLR(X, Y) + return mlr + } +} + +function print_lr(lr, var_name = "size") { + if (!!lr) return `Y = ${lr.weights[1][0].toFixed()} + ${lr.weights[0][0].toFixed()} * ${var_name}` + else return "no linear regression available" +} + +function print_summary_errors(data, compute_error, prefix = "") { + let max_error_current = 0; + let nb_error = 0 + for (datum of data) { + let error = compute_error(datum) + if (error > 0) nb_error += 1 + if (!isNaN(error)) max_error_current = Math.max(max_error_current, error) + } + console.log(`${prefix} nb of errors: ${nb_error} ; maximum error: ${max_error_current} ticks`) + return nb_error +} + +function print_model(model, var_name) { + return `Y = ${model.intercept} + ${model.coef} * ${var_name}` +} + +function predict_linear_model(model, x) { + if (isNaN(x)) return model.intercept + return model.intercept + model.coef * x +} + +function print_csv(dir, name, data_array, columns) { + fs.mkdirSync(dir, { recursive: true }) + fs.writeFileSync(path.format({ dir, name }), csv.stringify(data_array, { + header: true, + columns + })) } \ No newline at end of file