UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

222 lines (215 loc) 14.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.formatNanoseconds = formatNanoseconds; exports.stats2string = stats2string; exports.ultimateStats2String = ultimateStats2String; const assert_1 = require("../../util/assert"); const padSize = 15; function pad(string) { return String(string).padStart(padSize, ' '); } function formatNanoseconds(nanoseconds) { if (nanoseconds < 0) { return '??'; } else if (!Number.isFinite(nanoseconds)) { return nanoseconds > 0 ? '∞' : '-∞'; } const wholeNanos = typeof nanoseconds === 'bigint' ? nanoseconds : BigInt(Math.round(nanoseconds)); const nanos = wholeNanos % BigInt(1e+6); const wholeMillis = wholeNanos / BigInt(1e+6); const millis = wholeMillis % BigInt(1000); const wholeSeconds = wholeMillis / BigInt(1000); if (wholeSeconds > 0) { const nanoString = nanos > 0 ? `:${nanos}` : ''; return pad(`${wholeSeconds}.${String(millis).padStart(3, '0')}${nanoString} s`); } else { return pad(`${millis}:${String(nanos).padStart(6, '0')}ms`); } } function print(measurements, key) { const time = measurements.get(key); (0, assert_1.guard)(time !== undefined, `Measurement for ${JSON.stringify(key)} not found`); return formatNanoseconds(time); } function formatSummarizedTimeMeasure(measure) { if (measure === undefined) { return '??'; } return `${formatNanoseconds(measure.min)} - ${formatNanoseconds(measure.max)} (median: ${formatNanoseconds(measure.median)}, mean: ${formatNanoseconds(measure.mean)}, std: ${formatNanoseconds(measure.std)})`; } function roundTo(num, digits = 4) { const factor = Math.pow(10, digits); return Math.round(num * factor) / factor; } function asPercentage(num) { if (isNaN(num)) { return '??%'; } return pad(`${roundTo(num * 100, 3)}%`); } function asFloat(num) { return pad(roundTo(num)); } function formatSummarizedMeasure(measure, fmt = asFloat) { if (measure === undefined) { return '??'; } return `${fmt(measure.min)} - ${fmt(measure.max)} (median: ${fmt(measure.median)}, mean: ${fmt(measure.mean)}, std: ${fmt(measure.std)})`; } function printSummarizedMeasurements(stats, key) { const measure = stats.measurements.get(key); (0, assert_1.guard)(measure !== undefined, `Measurement for ${JSON.stringify(key)} not found`); return formatSummarizedTimeMeasure(measure); } function printCountSummarizedMeasurements(stats) { const range = `${stats.min} - ${stats.max}`.padStart(padSize, ' '); return `${range} (median: ${stats.median}, mean: ${stats.mean}, std: ${stats.std})`; } const units = ['bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']; // based on https://stackoverflow.com/a/39906526 function convertNumberToNiceBytes(x) { let n = Math.abs(x); let l = 0; while (n >= 1024 && ++l) { n = n / 1024; } return pad((x < 0 ? '-' : '') + n.toFixed(n < 10 && l > 0 ? 1 : 0) + ' ' + units[l]); } /** * Converts the given stats to a human-readable string. * You may have to {@link summarizeSlicerStats | summarize} the stats first. */ function stats2string(stats) { let result = ` Request: ${JSON.stringify(stats.request)} Shell init time: ${print(stats.commonMeasurements, 'initialize R session')} AST retrieval: ${print(stats.commonMeasurements, 'retrieve AST from R code')} AST retrieval per token: ${formatNanoseconds(stats.retrieveTimePerToken.normalized)} AST retrieval per R token: ${formatNanoseconds(stats.retrieveTimePerToken.raw)} AST normalization: ${print(stats.commonMeasurements, 'normalize R AST')} AST normalization per token: ${formatNanoseconds(stats.normalizeTimePerToken.normalized)} AST normalization per R token:${formatNanoseconds(stats.normalizeTimePerToken.raw)} Dataflow creation: ${print(stats.commonMeasurements, 'produce dataflow information')} Dataflow creation per token: ${formatNanoseconds(stats.dataflowTimePerToken.normalized)} Dataflow creation per R token:${formatNanoseconds(stats.dataflowTimePerToken.raw)} Total common time per token: ${formatNanoseconds(stats.totalCommonTimePerToken.normalized)} Total common time per R token:${formatNanoseconds(stats.totalCommonTimePerToken.raw)} Slicing summary for ${stats.perSliceMeasurements.numberOfSlices} slice${stats.perSliceMeasurements.numberOfSlices !== 1 ? 's' : ''}:`; if (stats.perSliceMeasurements.numberOfSlices > 0) { result += ` Total: ${printSummarizedMeasurements(stats.perSliceMeasurements, 'total')} Slice creation: ${printSummarizedMeasurements(stats.perSliceMeasurements, 'static slicing')} Slice creation per token in slice: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.sliceTimePerToken.normalized)} Slice creation per R token in slice:${formatSummarizedTimeMeasure(stats.perSliceMeasurements.sliceTimePerToken.raw)} Reconstruction: ${printSummarizedMeasurements(stats.perSliceMeasurements, 'reconstruct code')} Reconstruction per token in slice: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.reconstructTimePerToken.normalized)} Reconstruction per R token in slice:${formatSummarizedTimeMeasure(stats.perSliceMeasurements.reconstructTimePerToken.raw)} Total per token in slice: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.totalPerSliceTimePerToken.normalized)} Total per R token in slice: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.totalPerSliceTimePerToken.raw)} Used Slice Criteria Sizes: ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceCriteriaSizes)} Result Slice Sizes: Number of lines: ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceSize.lines)} Number of non-empty lines: ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceSize.nonEmptyLines)} Number of characters: ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceSize.characters)} Number of non whitespace characters: ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceSize.nonWhitespaceCharacters)} Number of auto selected lines: ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceSize.linesWithAutoSelected)} Number of R tokens: ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceSize.tokens)} Number of R tokens (w/o comments): ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceSize.tokensNoComments)} Normalized R tokens: ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceSize.normalizedTokens)} Normalized R tokens (w/o comments): ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceSize.normalizedTokensNoComments)} Number of dataflow nodes: ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceSize.dataflowNodes)} `; } return `${result} Shell close: ${print(stats.commonMeasurements, 'close R session')} Total: ${print(stats.commonMeasurements, 'total')} Input: Number of lines: ${pad(stats.input.numberOfLines)} Number of non empty lines: ${pad(stats.input.numberOfNonEmptyLines)} Number of characters: ${pad(stats.input.numberOfCharacters)} Number of characters (w/o comments): ${pad(stats.input.numberOfCharactersNoComments)} Number of non whitespace characters: ${pad(stats.input.numberOfNonWhitespaceCharacters)} Number of n. w. c. (w/o comments): ${pad(stats.input.numberOfNonWhitespaceCharactersNoComments)} Number of tokens: ${pad(stats.input.numberOfRTokens)} Number of tokens (w/o comments): ${pad(stats.input.numberOfRTokensNoComments)} Normalized R tokens: ${pad(stats.input.numberOfNormalizedTokens)} Normalized R tokens (w/o comments): ${pad(stats.input.numberOfNormalizedTokensNoComments)} Dataflow: Number of nodes: ${pad(stats.dataflow.numberOfNodes)} Number of edges: ${pad(stats.dataflow.numberOfEdges)} Number of calls: ${pad(stats.dataflow.numberOfCalls)} Number of function defs: ${pad(stats.dataflow.numberOfFunctionDefinitions)} Number of stored Vtx indices: ${pad(stats.dataflow.storedVertexIndices)} Number of stored Env indices: ${pad(stats.dataflow.storedEnvIndices)} Number of overwritten indices: ${pad(stats.dataflow.overwrittenIndices)} Size of graph: ${convertNumberToNiceBytes(stats.dataflow.sizeOfObject)}`; } function ultimateStats2String(stats) { const slice = stats.totalSlices > 0 ? `Slice summary for: Total: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.get('total'))} Slice creation: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.get('static slicing'))} Slice creation per token in slice: ${formatSummarizedTimeMeasure(stats.sliceTimePerToken.normalized)} Slice creation per R token in slice:${formatSummarizedTimeMeasure(stats.sliceTimePerToken.raw)} Reconstruction: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.get('reconstruct code'))} Reconstruction per token in slice: ${formatSummarizedTimeMeasure(stats.reconstructTimePerToken.normalized)} Reconstruction per R token in slice:${formatSummarizedTimeMeasure(stats.reconstructTimePerToken.raw)} Total per token in slice: ${formatSummarizedTimeMeasure(stats.totalPerSliceTimePerToken.normalized)} Total per R token in slice: ${formatSummarizedTimeMeasure(stats.totalPerSliceTimePerToken.raw)} Failed to Re-Parse: ${pad(stats.failedToRepParse)}/${stats.totalSlices} Times hit Threshold: ${pad(stats.timesHitThreshold)}/${stats.totalSlices} ${reduction2String('Reductions', stats.reduction)} ${reduction2String('Reductions without comments and empty lines', stats.reductionNoFluff)}` : 'No slices'; // Used Slice Criteria Sizes: ${formatSummarizedMeasure(stats.perSliceMeasurements.sliceCriteriaSizes)} return ` Summarized: ${stats.totalRequests} requests and ${stats.totalSlices} slices Shell init time: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('initialize R session'))} AST retrieval: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('retrieve AST from R code'))} AST retrieval per token: ${formatSummarizedTimeMeasure(stats.retrieveTimePerToken.normalized)} AST retrieval per R token: ${formatSummarizedTimeMeasure(stats.retrieveTimePerToken.raw)} AST normalization: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('normalize R AST'))} AST normalization per token: ${formatSummarizedTimeMeasure(stats.normalizeTimePerToken.normalized)} AST normalization per R token:${formatSummarizedTimeMeasure(stats.normalizeTimePerToken.raw)} Dataflow creation: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('produce dataflow information'))} Dataflow creation per token: ${formatSummarizedTimeMeasure(stats.dataflowTimePerToken.normalized)} Dataflow creation per R token:${formatSummarizedTimeMeasure(stats.dataflowTimePerToken.raw)} Total common time per token: ${formatSummarizedTimeMeasure(stats.totalCommonTimePerToken.normalized)} Total common time per R token:${formatSummarizedTimeMeasure(stats.totalCommonTimePerToken.raw)} ${slice} Shell close: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('close R session'))} Total: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('total'))} Input: Number of lines: ${formatSummarizedMeasure(stats.input.numberOfLines)} Number of non empty lines: ${formatSummarizedMeasure(stats.input.numberOfNonEmptyLines)} Number of characters: ${formatSummarizedMeasure(stats.input.numberOfCharacters)} Number of characters (w/o comments): ${formatSummarizedMeasure(stats.input.numberOfCharactersNoComments)} Number of non whitespace characters: ${formatSummarizedMeasure(stats.input.numberOfNonWhitespaceCharacters)} Number of n. w. c. (w/o comments): ${formatSummarizedMeasure(stats.input.numberOfNonWhitespaceCharactersNoComments)} Number of tokens: ${formatSummarizedMeasure(stats.input.numberOfRTokens)} Number of tokens (w/o comments): ${formatSummarizedMeasure(stats.input.numberOfRTokensNoComments)} Normalized R tokens: ${formatSummarizedMeasure(stats.input.numberOfNormalizedTokens)} Normalized R tokens (w/o comments): ${formatSummarizedMeasure(stats.input.numberOfNormalizedTokensNoComments)} Dataflow: Number of nodes: ${formatSummarizedMeasure(stats.dataflow.numberOfNodes)} Number of edges: ${formatSummarizedMeasure(stats.dataflow.numberOfEdges)} Number of calls: ${formatSummarizedMeasure(stats.dataflow.numberOfCalls)} Number of function defs: ${formatSummarizedMeasure(stats.dataflow.numberOfFunctionDefinitions)} Number of stored Vtx indices: ${formatSummarizedMeasure(stats.dataflow.storedVertexIndices)} Number of stored Env indices: ${formatSummarizedMeasure(stats.dataflow.storedEnvIndices)} Number of overwritten indices: ${formatSummarizedMeasure(stats.dataflow.overwrittenIndices)} Size of graph: ${formatSummarizedMeasure(stats.dataflow.sizeOfObject, convertNumberToNiceBytes)} `; } function reduction2String(title, reduction) { return ` ${title} (reduced by x%): Number of lines: ${formatSummarizedMeasure(reduction.numberOfLines, asPercentage)} Number of lines no auto: ${formatSummarizedMeasure(reduction.numberOfLinesNoAutoSelection, asPercentage)} Number of characters: ${formatSummarizedMeasure(reduction.numberOfCharacters, asPercentage)} Number of non whitespace characters: ${formatSummarizedMeasure(reduction.numberOfNonWhitespaceCharacters, asPercentage)} Number of R tokens: ${formatSummarizedMeasure(reduction.numberOfRTokens, asPercentage)} Normalized R tokens: ${formatSummarizedMeasure(reduction.numberOfNormalizedTokens, asPercentage)} Number of dataflow nodes: ${formatSummarizedMeasure(reduction.numberOfDataflowNodes, asPercentage)}`; } //# sourceMappingURL=print.js.map