UNPKG

@ethereumjs/vm

Version:
130 lines 4.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.emitEVMProfile = emitEVMProfile; /** * Emit EVM profile logs * @param logs * @param profileTitle * @hidden */ function emitEVMProfile(logs, profileTitle) { if (logs.length === 0) { return; } // Track total calls / time (ms) / gas let calls = 0; let totalMs = 0; let totalGas = 0; // Order of columns to report (see `EVMPerformanceLogOutput` type) const colOrder = [ 'tag', 'calls', 'avgTimePerCall', 'totalTime', 'staticGasUsed', 'dynamicGasUsed', 'gasUsed', 'staticGas', 'millionGasPerSecond', 'blocksPerSlot', ]; // The name of this column to report (saves space) const colNames = [ 'tag', 'calls', 'ms/call', 'total (ms)', 'sgas', 'dgas', 'total (s+d)', 'static fee', 'Mgas/s', 'BpS', ]; // Special padStr method which inserts whitespace left and right // This ensures that there is at least one whitespace between the columns (denoted by pipe `|` chars) function padStr(str, leftpad) { return ' ' + str.toString().padStart(leftpad, ' ') + ' '; } // Returns the string length of this column. Used to calculate how big the header / footer should be function strLen(str) { return padStr(str, 0).length - 2; } // Step one: calculate the length of each column const colLength = []; for (const entry of logs) { let ins = 0; colLength[ins] = Math.max(colLength[ins] ?? 0, strLen(colNames[ins])); for (const key of colOrder) { if (entry[key] !== undefined) { // If entry is available, max out the current column length (this will be the longest string of this column) colLength[ins] = Math.max(colLength[ins] ?? 0, strLen(entry[key])); ins++; // In this switch statement update the total calls / time / gas used switch (key) { case 'calls': calls += entry[key]; break; case 'totalTime': totalMs += entry[key]; break; case 'gasUsed': totalGas += entry[key]; break; } } } } // Ensure that the column names also fit on the column length for (const i in colLength) { colLength[i] = Math.max(colLength[i] ?? 0, strLen(colNames[i])); } // Calculate the total header length // This is done by summing all columns together, plus adding three extra chars per column (two whitespace, one pipe) // Remove the final pipe character since this is included in the header string (so subtract one) const headerLength = colLength.reduce((pv, cv) => pv + cv, 0) + colLength.length * 3 - 1; const blockGasLimit = 30000000; // Block gas limit const slotTime = 12000; // Time in milliseconds (!) per slot // Normalize constant to check if execution time is above one block per slot (>=1) or not (<1) const bpsNormalizer = blockGasLimit / slotTime; const avgGas = totalGas / totalMs; // Gas per millisecond const mGasSAvg = Math.round(avgGas) / 1e3; const bpSAvg = Math.round((avgGas / bpsNormalizer) * 1e3) / 1e3; // Write the profile title // eslint-disable-next-line console.log('+== ' + profileTitle + ' ==+'); // Write the summary of this profile // eslint-disable-next-line console.log(`+== Calls: ${calls}, Total time: ${Math.round(totalMs * 1e3) / 1e3}ms, Total gas: ${totalGas}, MGas/s: ${mGasSAvg}, Blocks per Slot (BpS): ${bpSAvg} ==+`); // Generate and write the header const header = '|' + '-'.repeat(headerLength) + '|'; // eslint-disable-next-line console.log(header); // Write the columns let str = ''; for (const i in colLength) { str += '|' + padStr(colNames[i], colLength[i]); } str += '|'; // eslint-disable-next-line console.log(str); // Write each profile entry for (const entry of logs) { let str = ''; let i = 0; for (const key of colOrder) { if (entry[key] !== undefined) { str += '|' + padStr(entry[key], colLength[i]); i++; } } str += '|'; // eslint-disable-next-line console.log(str); } // Finally, write the footer const footer = '+' + '-'.repeat(headerLength) + '+'; // eslint-disable-next-line console.log(footer); } //# sourceMappingURL=emitEVMProfile.js.map