@eagleoutice/flowr 2.0.2 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -51,6 +51,7 @@ export declare class BenchmarkSlicer {
51
51
  /** Measures all data recorded *once* per slicer (complete setup up to the dataflow graph creation) */
52
52
  private readonly commonMeasurements;
53
53
  private readonly perSliceMeasurements;
54
+ private readonly deltas;
54
55
  private readonly shell;
55
56
  private stats;
56
57
  private loadedXml;
@@ -19,6 +19,7 @@ const default_pipelines_1 = require("../core/steps/pipeline/default-pipelines");
19
19
  const retriever_1 = require("../r-bridge/retriever");
20
20
  const collect_all_1 = require("../slicing/criterion/collect-all");
21
21
  const visitor_1 = require("../r-bridge/lang-4.x/ast/model/processing/visitor");
22
+ const size_of_1 = require("./stats/size-of");
22
23
  exports.benchmarkLogger = log_1.log.getSubLogger({ name: 'benchmark' });
23
24
  /**
24
25
  * A slicer that can be used to slice exactly one file (multiple times).
@@ -33,6 +34,7 @@ class BenchmarkSlicer {
33
34
  /** Measures all data recorded *once* per slicer (complete setup up to the dataflow graph creation) */
34
35
  commonMeasurements = new stopwatch_1.Measurements();
35
36
  perSliceMeasurements = new Map();
37
+ deltas = new Map();
36
38
  shell;
37
39
  stats;
38
40
  loadedXml;
@@ -105,8 +107,8 @@ class BenchmarkSlicer {
105
107
  const split = loadedContent.split('\n');
106
108
  const nonWhitespace = (0, strings_1.withoutWhitespace)(loadedContent).length;
107
109
  this.stats = {
108
- commonMeasurements: new Map(),
109
110
  perSliceMeasurements: this.perSliceMeasurements,
111
+ memory: this.deltas,
110
112
  request,
111
113
  input: {
112
114
  numberOfLines: split.length,
@@ -124,8 +126,15 @@ class BenchmarkSlicer {
124
126
  numberOfNodes: [...this.dataflow.graph.vertices(true)].length,
125
127
  numberOfEdges: numberOfEdges,
126
128
  numberOfCalls: numberOfCalls,
127
- numberOfFunctionDefinitions: numberOfDefinitions
128
- }
129
+ numberOfFunctionDefinitions: numberOfDefinitions,
130
+ sizeOfObject: (0, size_of_1.getSizeOfDfGraph)(this.dataflow.graph)
131
+ },
132
+ // these are all properly initialized in finish()
133
+ commonMeasurements: new Map(),
134
+ retrieveTimePerToken: { raw: 0, normalized: 0 },
135
+ normalizeTimePerToken: { raw: 0, normalized: 0 },
136
+ dataflowTimePerToken: { raw: 0, normalized: 0 },
137
+ totalCommonTimePerToken: { raw: 0, normalized: 0 }
129
138
  };
130
139
  }
131
140
  /**
@@ -177,7 +186,15 @@ class BenchmarkSlicer {
177
186
  }
178
187
  /** Bridging the gap between the new internal and the old names for the benchmarking */
179
188
  async measureCommonStep(expectedStep, keyToMeasure) {
189
+ const memoryInit = process.memoryUsage();
180
190
  const { result } = await this.commonMeasurements.measureAsync(keyToMeasure, () => this.pipeline.nextStep(expectedStep));
191
+ const memoryEnd = process.memoryUsage();
192
+ this.deltas.set(keyToMeasure, {
193
+ heap: memoryEnd.heapUsed - memoryInit.heapUsed,
194
+ rss: memoryEnd.rss - memoryInit.rss,
195
+ external: memoryEnd.external - memoryInit.external,
196
+ buffs: memoryEnd.arrayBuffers - memoryInit.arrayBuffers
197
+ });
181
198
  return result;
182
199
  }
183
200
  async measureSliceStep(expectedStep, measure, keyToMeasure) {
@@ -221,6 +238,25 @@ class BenchmarkSlicer {
221
238
  this.finished = true;
222
239
  }
223
240
  this.stats.commonMeasurements = this.commonMeasurements.get();
241
+ const retrieveTime = Number(this.stats.commonMeasurements.get('retrieve AST from R code'));
242
+ const normalizeTime = Number(this.stats.commonMeasurements.get('normalize R AST'));
243
+ const dataflowTime = Number(this.stats.commonMeasurements.get('produce dataflow information'));
244
+ this.stats.retrieveTimePerToken = {
245
+ raw: retrieveTime / this.stats.input.numberOfRTokens,
246
+ normalized: retrieveTime / this.stats.input.numberOfNormalizedTokens
247
+ };
248
+ this.stats.normalizeTimePerToken = {
249
+ raw: normalizeTime / this.stats.input.numberOfRTokens,
250
+ normalized: normalizeTime / this.stats.input.numberOfNormalizedTokens
251
+ };
252
+ this.stats.dataflowTimePerToken = {
253
+ raw: dataflowTime / this.stats.input.numberOfRTokens,
254
+ normalized: dataflowTime / this.stats.input.numberOfNormalizedTokens
255
+ };
256
+ this.stats.totalCommonTimePerToken = {
257
+ raw: (retrieveTime + normalizeTime + dataflowTime) / this.stats.input.numberOfRTokens,
258
+ normalized: (retrieveTime + normalizeTime + dataflowTime) / this.stats.input.numberOfNormalizedTokens
259
+ };
224
260
  return {
225
261
  stats: this.stats,
226
262
  parse: this.loadedXml,
@@ -1,4 +1,5 @@
1
1
  import type { SummarizedSlicerStats, UltimateSlicerStats } from '../summarizer/data';
2
+ export declare function formatNanoseconds(nanoseconds: bigint | number): string;
2
3
  /**
3
4
  * Converts the given stats to a human-readable string.
4
5
  * You may have to {@link summarizeSlicerStats | summarize} the stats first.
@@ -1,26 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ultimateStats2String = exports.stats2string = void 0;
3
+ exports.ultimateStats2String = exports.stats2string = exports.formatNanoseconds = void 0;
4
4
  const assert_1 = require("../../util/assert");
5
5
  const padSize = 15;
6
6
  function pad(string) {
7
7
  return String(string).padStart(padSize, ' ');
8
8
  }
9
- function divWithRest(dividend, divisor) {
10
- return [dividend / divisor, dividend % divisor];
11
- }
12
9
  function formatNanoseconds(nanoseconds) {
13
10
  if (nanoseconds < 0) {
14
11
  return '??';
15
12
  }
16
- const [seconds, rest] = divWithRest(typeof nanoseconds === 'number' ? BigInt(Math.round(nanoseconds)) : nanoseconds, BigInt(1e9));
17
- const [milliseconds, remainingNanoseconds] = divWithRest(rest, BigInt(1e6));
18
- const secondsStr = seconds > 0 ? `${String(seconds).padStart(2, '0')}.` : '';
19
- const millisecondsStr = seconds > 0 ? `${String(milliseconds).padStart(3, '0')}:` : `${String(milliseconds)}:`;
20
- const nanoStr = String(remainingNanoseconds).padEnd(3, '0').substring(0, 3);
21
- const unit = seconds === 0n ? 'ms' : ' s'; /* space for padding */
22
- return pad(`${secondsStr}${millisecondsStr}${nanoStr}${unit}`);
13
+ const wholeNanos = typeof nanoseconds === 'bigint' ? nanoseconds : BigInt(Math.round(nanoseconds));
14
+ const nanos = wholeNanos % BigInt(1e+6);
15
+ const wholeMillis = wholeNanos / BigInt(1e+6);
16
+ const millis = wholeMillis % BigInt(1000);
17
+ const wholeSeconds = wholeMillis / BigInt(1000);
18
+ if (wholeSeconds > 0) {
19
+ const nanoString = nanos > 0 ? `:${nanos}` : '';
20
+ return pad(`${wholeSeconds}.${String(millis).padStart(3, '0')}${nanoString} s`);
21
+ }
22
+ else {
23
+ return pad(`${millis}:${String(nanos).padStart(6, '0')}ms`);
24
+ }
23
25
  }
26
+ exports.formatNanoseconds = formatNanoseconds;
24
27
  function print(measurements, key) {
25
28
  const time = measurements.get(key);
26
29
  (0, assert_1.guard)(time !== undefined, `Measurement for ${JSON.stringify(key)} not found`);
@@ -61,6 +64,16 @@ function printCountSummarizedMeasurements(stats) {
61
64
  const range = `${stats.min} - ${stats.max}`.padStart(padSize, ' ');
62
65
  return `${range} (median: ${stats.median}, mean: ${stats.mean}, std: ${stats.std})`;
63
66
  }
67
+ const units = ['bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
68
+ // based on https://stackoverflow.com/a/39906526
69
+ function convertNumberToNiceBytes(x) {
70
+ let n = Math.abs(x);
71
+ let l = 0;
72
+ while (n >= 1024 && ++l) {
73
+ n = n / 1024;
74
+ }
75
+ return pad((x < 0 ? '-' : '') + n.toFixed(n < 10 && l > 0 ? 1 : 0) + ' ' + units[l]);
76
+ }
64
77
  /**
65
78
  * Converts the given stats to a human-readable string.
66
79
  * You may have to {@link summarizeSlicerStats | summarize} the stats first.
@@ -70,16 +83,30 @@ function stats2string(stats) {
70
83
  Request: ${JSON.stringify(stats.request)}
71
84
  Shell init time: ${print(stats.commonMeasurements, 'initialize R session')}
72
85
  AST retrieval: ${print(stats.commonMeasurements, 'retrieve AST from R code')}
86
+ AST retrieval per token: ${formatNanoseconds(stats.retrieveTimePerToken.normalized)}
87
+ AST retrieval per R token: ${formatNanoseconds(stats.retrieveTimePerToken.raw)}
73
88
  AST normalization: ${print(stats.commonMeasurements, 'normalize R AST')}
89
+ AST normalization per token: ${formatNanoseconds(stats.normalizeTimePerToken.normalized)}
90
+ AST normalization per R token:${formatNanoseconds(stats.normalizeTimePerToken.raw)}
74
91
  Dataflow creation: ${print(stats.commonMeasurements, 'produce dataflow information')}
92
+ Dataflow creation per token: ${formatNanoseconds(stats.dataflowTimePerToken.normalized)}
93
+ Dataflow creation per R token:${formatNanoseconds(stats.dataflowTimePerToken.raw)}
94
+ Total common time per token: ${formatNanoseconds(stats.totalCommonTimePerToken.normalized)}
95
+ Total common time per R token:${formatNanoseconds(stats.totalCommonTimePerToken.raw)}
75
96
 
76
97
  Slicing summary for ${stats.perSliceMeasurements.numberOfSlices} slice${stats.perSliceMeasurements.numberOfSlices !== 1 ? 's' : ''}:`;
77
98
  if (stats.perSliceMeasurements.numberOfSlices > 0) {
78
99
  result += `
79
- Total: ${printSummarizedMeasurements(stats.perSliceMeasurements, 'total')}
80
- Slice creation: ${printSummarizedMeasurements(stats.perSliceMeasurements, 'static slicing')}
81
- Reconstruction: ${printSummarizedMeasurements(stats.perSliceMeasurements, 'reconstruct code')}
82
- Used Slice Criteria Sizes: ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceCriteriaSizes)}
100
+ Total: ${printSummarizedMeasurements(stats.perSliceMeasurements, 'total')}
101
+ Slice creation: ${printSummarizedMeasurements(stats.perSliceMeasurements, 'static slicing')}
102
+ Slice creation per token in slice: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.sliceTimePerToken.normalized)}
103
+ Slice creation per R token in slice:${formatSummarizedTimeMeasure(stats.perSliceMeasurements.sliceTimePerToken.raw)}
104
+ Reconstruction: ${printSummarizedMeasurements(stats.perSliceMeasurements, 'reconstruct code')}
105
+ Reconstruction per token in slice: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.reconstructTimePerToken.normalized)}
106
+ Reconstruction per R token in slice:${formatSummarizedTimeMeasure(stats.perSliceMeasurements.reconstructTimePerToken.raw)}
107
+ Total per token in slice: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.totalPerSliceTimePerToken.normalized)}
108
+ Total per R token in slice: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.totalPerSliceTimePerToken.raw)}
109
+ Used Slice Criteria Sizes: ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceCriteriaSizes)}
83
110
  Result Slice Sizes:
84
111
  Number of lines: ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceSize.lines)}
85
112
  Number of non-empty lines: ${printCountSummarizedMeasurements(stats.perSliceMeasurements.sliceSize.nonEmptyLines)}
@@ -113,7 +140,8 @@ Dataflow:
113
140
  Number of nodes: ${pad(stats.dataflow.numberOfNodes)}
114
141
  Number of edges: ${pad(stats.dataflow.numberOfEdges)}
115
142
  Number of calls: ${pad(stats.dataflow.numberOfCalls)}
116
- Number of function defs: ${pad(stats.dataflow.numberOfFunctionDefinitions)}`;
143
+ Number of function defs: ${pad(stats.dataflow.numberOfFunctionDefinitions)}
144
+ Size of graph: ${convertNumberToNiceBytes(stats.dataflow.sizeOfObject)}`;
117
145
  }
118
146
  exports.stats2string = stats2string;
119
147
  function ultimateStats2String(stats) {
@@ -122,15 +150,29 @@ function ultimateStats2String(stats) {
122
150
  Summarized: ${stats.totalRequests} requests and ${stats.totalSlices} slices
123
151
  Shell init time: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('initialize R session'))}
124
152
  AST retrieval: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('retrieve AST from R code'))}
153
+ AST retrieval per token: ${formatSummarizedTimeMeasure(stats.retrieveTimePerToken.normalized)}
154
+ AST retrieval per R token: ${formatSummarizedTimeMeasure(stats.retrieveTimePerToken.raw)}
125
155
  AST normalization: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('normalize R AST'))}
156
+ AST normalization per token: ${formatSummarizedTimeMeasure(stats.normalizeTimePerToken.normalized)}
157
+ AST normalization per R token:${formatSummarizedTimeMeasure(stats.normalizeTimePerToken.raw)}
126
158
  Dataflow creation: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('produce dataflow information'))}
159
+ Dataflow creation per token: ${formatSummarizedTimeMeasure(stats.dataflowTimePerToken.normalized)}
160
+ Dataflow creation per R token:${formatSummarizedTimeMeasure(stats.dataflowTimePerToken.raw)}
161
+ Total common time per token: ${formatSummarizedTimeMeasure(stats.totalCommonTimePerToken.normalized)}
162
+ Total common time per R token:${formatSummarizedTimeMeasure(stats.totalCommonTimePerToken.raw)}
127
163
 
128
164
  Slice summary for:
129
- Total: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.get('total'))}
130
- Slice creation: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.get('static slicing'))}
131
- Reconstruction: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.get('reconstruct code'))}
132
- Failed to Re-Parse: ${pad(stats.failedToRepParse)}/${stats.totalSlices}
133
- Times hit Threshold: ${pad(stats.timesHitThreshold)}/${stats.totalSlices}
165
+ Total: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.get('total'))}
166
+ Slice creation: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.get('static slicing'))}
167
+ Slice creation per token in slice: ${formatSummarizedTimeMeasure(stats.sliceTimePerToken.normalized)}
168
+ Slice creation per R token in slice:${formatSummarizedTimeMeasure(stats.sliceTimePerToken.raw)}
169
+ Reconstruction: ${formatSummarizedTimeMeasure(stats.perSliceMeasurements.get('reconstruct code'))}
170
+ Reconstruction per token in slice: ${formatSummarizedTimeMeasure(stats.reconstructTimePerToken.normalized)}
171
+ Reconstruction per R token in slice:${formatSummarizedTimeMeasure(stats.reconstructTimePerToken.raw)}
172
+ Total per token in slice: ${formatSummarizedTimeMeasure(stats.totalPerSliceTimePerToken.normalized)}
173
+ Total per R token in slice: ${formatSummarizedTimeMeasure(stats.totalPerSliceTimePerToken.raw)}
174
+ Failed to Re-Parse: ${pad(stats.failedToRepParse)}/${stats.totalSlices}
175
+ Times hit Threshold: ${pad(stats.timesHitThreshold)}/${stats.totalSlices}
134
176
  ${reduction2String('Reductions', stats.reduction)}
135
177
  ${reduction2String('Reductions without comments and empty lines', stats.reductionNoFluff)}
136
178
 
@@ -153,7 +195,9 @@ Dataflow:
153
195
  Number of nodes: ${formatSummarizedMeasure(stats.dataflow.numberOfNodes)}
154
196
  Number of edges: ${formatSummarizedMeasure(stats.dataflow.numberOfEdges)}
155
197
  Number of calls: ${formatSummarizedMeasure(stats.dataflow.numberOfCalls)}
156
- Number of function defs: ${formatSummarizedMeasure(stats.dataflow.numberOfFunctionDefinitions)}`;
198
+ Number of function defs: ${formatSummarizedMeasure(stats.dataflow.numberOfFunctionDefinitions)}
199
+ Size of graph: ${formatSummarizedMeasure(stats.dataflow.sizeOfObject, convertNumberToNiceBytes)}
200
+ `;
157
201
  }
158
202
  exports.ultimateStats2String = ultimateStats2String;
159
203
  function reduction2String(title, reduction) {
@@ -0,0 +1,3 @@
1
+ import type { DataflowGraph } from '../../dataflow/graph/graph';
2
+ /** Returns the size of the given df graph in bytes (without sharing in-memory) */
3
+ export declare function getSizeOfDfGraph(df: DataflowGraph): number;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getSizeOfDfGraph = void 0;
7
+ const environment_1 = require("../../dataflow/environments/environment");
8
+ const object_sizeof_1 = __importDefault(require("object-sizeof"));
9
+ /* we have to kill all processors linked in the default environment as they cannot be serialized and they are shared anyway */
10
+ function killBuiltInEnv(env) {
11
+ if (env === undefined) {
12
+ return undefined;
13
+ }
14
+ else if (env.id === environment_1.BuiltInEnvironment.id) {
15
+ /* in this case, the reference would be shared for sure */
16
+ return {
17
+ id: env.id,
18
+ parent: killBuiltInEnv(env.parent),
19
+ memory: new Map()
20
+ };
21
+ }
22
+ const memory = new Map();
23
+ for (const [k, v] of env.memory) {
24
+ memory.set(k, v.filter(v => !v.kind.startsWith('built-in') && !('processor' in v)));
25
+ }
26
+ return {
27
+ id: env.id,
28
+ parent: killBuiltInEnv(env.parent),
29
+ memory
30
+ };
31
+ }
32
+ /** Returns the size of the given df graph in bytes (without sharing in-memory) */
33
+ function getSizeOfDfGraph(df) {
34
+ const verts = [];
35
+ for (const [, v] of df.vertices(true)) {
36
+ let vertex = v;
37
+ if (vertex.environment) {
38
+ vertex = {
39
+ ...vertex,
40
+ environment: {
41
+ ...vertex.environment,
42
+ current: killBuiltInEnv(v.environment.current)
43
+ }
44
+ };
45
+ }
46
+ if (vertex.tag === "function-definition" /* VertexType.FunctionDefinition */) {
47
+ vertex = {
48
+ ...vertex,
49
+ subflow: {
50
+ ...vertex.subflow,
51
+ environment: {
52
+ ...vertex.subflow.environment,
53
+ current: killBuiltInEnv(vertex.subflow.environment.current)
54
+ }
55
+ }
56
+ };
57
+ }
58
+ vertex = {
59
+ ...vertex,
60
+ /* shared anyway by using constants */
61
+ tag: 0
62
+ };
63
+ verts.push(vertex);
64
+ }
65
+ return (0, object_sizeof_1.default)([...verts, ...df.edges()]);
66
+ }
67
+ exports.getSizeOfDfGraph = getSizeOfDfGraph;
68
+ //# sourceMappingURL=size-of.js.map
@@ -2,6 +2,8 @@ import type { SingleSlicingCriterion, SlicingCriteria } from '../../slicing/crit
2
2
  import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
3
3
  import type { ReconstructionResult } from '../../reconstruct/reconstruct';
4
4
  import type { RParseRequestFromFile, RParseRequestFromText } from '../../r-bridge/retriever';
5
+ import type { TimePerToken } from '../summarizer/data';
6
+ import type { MergeableRecord } from '../../util/objects';
5
7
  export declare const CommonSlicerMeasurements: readonly ["initialize R session", "retrieve AST from R code", "normalize R AST", "produce dataflow information", "close R session", "total"];
6
8
  export type CommonSlicerMeasurements = typeof CommonSlicerMeasurements[number];
7
9
  export declare const PerSliceMeasurements: readonly ["static slicing", "reconstruct code", "total"];
@@ -34,6 +36,17 @@ export interface SlicerStatsDataflow<T = number> {
34
36
  numberOfEdges: T;
35
37
  numberOfCalls: T;
36
38
  numberOfFunctionDefinitions: T;
39
+ sizeOfObject: T;
40
+ }
41
+ /**
42
+ * Please note, that these measurement can be negative as there is no guarantee that the memory usage will increase
43
+ * due to, e.g., garbage collection.
44
+ */
45
+ export interface BenchmarkMemoryMeasurement<T = number> extends MergeableRecord {
46
+ heap: T;
47
+ rss: T;
48
+ external: T;
49
+ buffs: T;
37
50
  }
38
51
  /**
39
52
  * The statistics that are collected by the {@link BenchmarkSlicer} and used for benchmarking.
@@ -41,7 +54,12 @@ export interface SlicerStatsDataflow<T = number> {
41
54
  export interface SlicerStats {
42
55
  commonMeasurements: Map<CommonSlicerMeasurements, ElapsedTime>;
43
56
  perSliceMeasurements: Map<SlicingCriteria, PerSliceStats>;
57
+ memory: Map<CommonSlicerMeasurements, BenchmarkMemoryMeasurement>;
44
58
  request: RParseRequestFromFile | RParseRequestFromText;
45
59
  input: SlicerStatsInput;
46
60
  dataflow: SlicerStatsDataflow;
61
+ retrieveTimePerToken: TimePerToken<number>;
62
+ normalizeTimePerToken: TimePerToken<number>;
63
+ dataflowTimePerToken: TimePerToken<number>;
64
+ totalCommonTimePerToken: TimePerToken<number>;
47
65
  }
@@ -31,12 +31,19 @@ export interface Reduction<T = number> {
31
31
  numberOfNormalizedTokens: T;
32
32
  numberOfDataflowNodes: T;
33
33
  }
34
+ export interface TimePerToken<T = SummarizedMeasurement> {
35
+ raw: T;
36
+ normalized: T;
37
+ }
34
38
  export interface SummarizedPerSliceStats {
35
39
  /** number of total slicing calls */
36
40
  numberOfSlices: number;
37
41
  /** statistics on the used slicing criteria (number of ids within criteria etc.) */
38
42
  sliceCriteriaSizes: SummarizedMeasurement;
39
43
  measurements: Map<PerSliceMeasurements, SummarizedMeasurement>;
44
+ sliceTimePerToken: TimePerToken;
45
+ reconstructTimePerToken: TimePerToken;
46
+ totalPerSliceTimePerToken: TimePerToken;
40
47
  reduction: Reduction<SummarizedMeasurement>;
41
48
  /** reduction, but without taking into account comments and empty lines */
42
49
  reductionNoFluff: Reduction<SummarizedMeasurement>;
@@ -51,6 +58,13 @@ export interface UltimateSlicerStats {
51
58
  totalSlices: number;
52
59
  commonMeasurements: Map<CommonSlicerMeasurements, SummarizedMeasurement>;
53
60
  perSliceMeasurements: Map<PerSliceMeasurements, SummarizedMeasurement>;
61
+ retrieveTimePerToken: TimePerToken;
62
+ normalizeTimePerToken: TimePerToken;
63
+ dataflowTimePerToken: TimePerToken;
64
+ totalCommonTimePerToken: TimePerToken;
65
+ sliceTimePerToken: TimePerToken;
66
+ reconstructTimePerToken: TimePerToken;
67
+ totalPerSliceTimePerToken: TimePerToken;
54
68
  /** sum */
55
69
  failedToRepParse: number;
56
70
  /** sum */
@@ -1,3 +1,3 @@
1
1
  /// <reference types="node" />
2
- export declare function processRunMeasurement(line: Buffer, fileNum: number, lineNum: number, summarizedText: string, outputPath: string): Promise<void>;
3
- export declare function processSummarizedFileMeasurement(file: string, summariesFile: string, outputPath: string): void;
2
+ export declare function processRunMeasurement(line: Buffer, fileNum: number, lineNum: number, textOutputAppendPath: string, rawOutputPath: string): Promise<void>;
3
+ export declare function processSummarizedRunMeasurement(runNum: number, summarizedFiles: string[], appendPath: string): void;
@@ -3,27 +3,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.processSummarizedFileMeasurement = exports.processRunMeasurement = void 0;
6
+ exports.processSummarizedRunMeasurement = exports.processRunMeasurement = void 0;
7
7
  const fs_1 = __importDefault(require("fs"));
8
8
  const process_1 = require("../second-phase/process");
9
9
  const process_2 = require("./process");
10
10
  const assert_1 = require("../../../util/assert");
11
11
  const ansi_1 = require("../../../util/ansi");
12
12
  const json_1 = require("../../../util/json");
13
- const files_1 = require("../../../util/files");
14
13
  const print_1 = require("../../stats/print");
15
- async function processRunMeasurement(line, fileNum, lineNum, summarizedText, outputPath) {
14
+ async function processRunMeasurement(line, fileNum, lineNum, textOutputAppendPath, rawOutputPath) {
16
15
  let got = JSON.parse(line.toString());
17
16
  console.log(`[file ${fileNum}, line ${lineNum}] Summarize for ${got.filename}`);
18
17
  // now we have to recover the maps and bigints :C
19
18
  got = {
20
- filename: got.filename,
21
- 'file-id': got['file-id'],
22
- 'run-num': got['run-num'],
19
+ ...got,
23
20
  stats: {
24
- input: got.stats.input,
25
- request: got.stats.request,
26
- dataflow: got.stats.dataflow,
21
+ ...got.stats,
22
+ memory: new Map(got.stats.memory
23
+ .map(([k, v]) => [k, v])),
27
24
  commonMeasurements: new Map(got.stats.commonMeasurements
28
25
  .map(([k, v]) => {
29
26
  (0, assert_1.guard)(v.endsWith('n'), 'Expected a bigint');
@@ -38,28 +35,31 @@ async function processRunMeasurement(line, fileNum, lineNum, summarizedText, out
38
35
  let atSliceNumber = 0;
39
36
  const summarized = await (0, process_2.summarizeSlicerStats)(got.stats, (criterion, stats) => {
40
37
  console.log(`${ansi_1.escape}1F${ansi_1.escape}1G${ansi_1.escape}2K [${++atSliceNumber}/${totalSlices}] Summarizing ${JSON.stringify(criterion)} (reconstructed has ${stats.reconstructedCode.code.length} characters)`);
38
+ if (stats.reconstructedCode.code.length < 50) {
39
+ console.log(`Reconstructed code: ${stats.reconstructedCode.code}`);
40
+ }
41
41
  });
42
- console.log(` - Append raw summary to ${outputPath}`);
43
- fs_1.default.appendFileSync(outputPath, `${JSON.stringify({
42
+ console.log(` - Write raw summary to ${rawOutputPath}`);
43
+ fs_1.default.writeFileSync(rawOutputPath, `${JSON.stringify({
44
44
  filename: got.filename,
45
45
  'file-id': got['file-id'],
46
46
  'run-num': got['run-num'],
47
47
  summarize: summarized
48
48
  }, json_1.jsonReplacer)}\n`);
49
- console.log(` - Append textual summary to ${summarizedText}`);
50
- fs_1.default.appendFileSync(summarizedText, `${(0, print_1.stats2string)(summarized)}\n`);
49
+ console.log(` - Append textual summary to ${textOutputAppendPath}`);
50
+ fs_1.default.appendFileSync(textOutputAppendPath, `${(0, print_1.stats2string)(summarized)}\n`);
51
51
  }
52
52
  exports.processRunMeasurement = processRunMeasurement;
53
- function processSummarizedFileMeasurement(file, summariesFile, outputPath) {
54
- console.log(`Summarize all runs for ${file}`);
53
+ function processSummarizedRunMeasurement(runNum, summarizedFiles, appendPath) {
54
+ console.log(`Summarizing all file statistics for run ${runNum}`);
55
55
  const summaries = [];
56
- (0, files_1.readLineByLineSync)(summariesFile, l => (0, process_1.processNextSummary)(l, summaries));
57
- fs_1.default.appendFileSync(outputPath, `${JSON.stringify({
58
- filename: file,
59
- summarize: (0, process_1.summarizeAllSummarizedStats)(summaries)
60
- }, json_1.jsonReplacer)}\n`);
56
+ for (const file of summarizedFiles) {
57
+ (0, process_1.processNextSummary)(fs_1.default.readFileSync(file), summaries);
58
+ }
59
+ fs_1.default.appendFileSync(appendPath, `${JSON.stringify((0, process_1.summarizeAllSummarizedStats)(summaries), json_1.jsonReplacer)}\n`);
60
+ console.log(`Appended summary of run ${runNum} to ${appendPath}`);
61
61
  }
62
- exports.processSummarizedFileMeasurement = processSummarizedFileMeasurement;
62
+ exports.processSummarizedRunMeasurement = processSummarizedRunMeasurement;
63
63
  function mapPerSliceStats(k, v) {
64
64
  return [k, {
65
65
  reconstructedCode: v.reconstructedCode,
@@ -1,4 +1,4 @@
1
- import type { Reduction, SummarizedSlicerStats } from '../data';
1
+ import type { Reduction, SummarizedSlicerStats, TimePerToken } from '../data';
2
2
  import type { SummarizedMeasurement } from '../../../util/summarizer';
3
3
  import type { PerSliceStats, SlicerStats } from '../../stats/stats';
4
4
  import type { SlicingCriteria } from '../../../slicing/criterion/parse';
@@ -9,3 +9,5 @@ import type { SlicingCriteria } from '../../../slicing/criterion/parse';
9
9
  export declare function summarizeSlicerStats(stats: SlicerStats, report?: (criteria: SlicingCriteria, stats: PerSliceStats) => void): Promise<Readonly<SummarizedSlicerStats>>;
10
10
  export declare function summarizeSummarizedMeasurement(data: SummarizedMeasurement[]): SummarizedMeasurement;
11
11
  export declare function summarizeSummarizedReductions(reductions: Reduction<SummarizedMeasurement>[]): Reduction<SummarizedMeasurement>;
12
+ export declare function summarizeSummarizedTimePerToken(times: TimePerToken[]): TimePerToken;
13
+ export declare function summarizeTimePerToken(times: TimePerToken<number>[]): TimePerToken;
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.summarizeSummarizedReductions = exports.summarizeSummarizedMeasurement = exports.summarizeSlicerStats = void 0;
29
+ exports.summarizeTimePerToken = exports.summarizeSummarizedTimePerToken = exports.summarizeSummarizedReductions = exports.summarizeSummarizedMeasurement = exports.summarizeSlicerStats = void 0;
30
30
  const tmp = __importStar(require("tmp"));
31
31
  const fs_1 = __importDefault(require("fs"));
32
32
  const defaultmap_1 = require("../../../util/defaultmap");
@@ -92,10 +92,12 @@ function calculateReductionForSlice(input, dataflow, perSlice, ignoreFluff) {
92
92
  */
93
93
  async function summarizeSlicerStats(stats, report = () => {
94
94
  }) {
95
- const perSliceStats = stats.perSliceMeasurements;
96
95
  const collect = new defaultmap_1.DefaultMap(() => []);
97
96
  const sizeOfSliceCriteria = [];
98
97
  const reParseShellSession = new shell_1.RShell();
98
+ const sliceTimes = [];
99
+ const reconstructTimes = [];
100
+ const totalTimes = [];
99
101
  const reductions = [];
100
102
  const reductionsNoFluff = [];
101
103
  let failedOutputs = 0;
@@ -114,7 +116,7 @@ async function summarizeSlicerStats(stats, report = () => {
114
116
  dataflowNodes: []
115
117
  };
116
118
  let timesHitThreshold = 0;
117
- for (const [criteria, perSliceStat] of perSliceStats) {
119
+ for (const [criteria, perSliceStat] of stats.perSliceMeasurements) {
118
120
  report(criteria, perSliceStat);
119
121
  for (const measure of perSliceStat.measurements) {
120
122
  collect.get(measure[0]).push(Number(measure[1]));
@@ -177,6 +179,20 @@ async function summarizeSlicerStats(stats, report = () => {
177
179
  };
178
180
  reductions.push(calculateReductionForSlice(stats.input, stats.dataflow, perSlice, false));
179
181
  reductionsNoFluff.push(calculateReductionForSlice(stats.input, stats.dataflow, perSlice, true));
182
+ const sliceTime = Number(perSliceStat.measurements.get('static slicing'));
183
+ const reconstructTime = Number(perSliceStat.measurements.get('reconstruct code'));
184
+ sliceTimes.push({
185
+ raw: sliceTime / numberOfRTokens,
186
+ normalized: sliceTime / numberOfNormalizedTokens
187
+ });
188
+ reconstructTimes.push({
189
+ raw: reconstructTime / numberOfRTokens,
190
+ normalized: reconstructTime / numberOfNormalizedTokens
191
+ });
192
+ totalTimes.push({
193
+ raw: (sliceTime + reconstructTime) / numberOfRTokens,
194
+ normalized: (sliceTime + reconstructTime) / numberOfNormalizedTokens
195
+ });
180
196
  }
181
197
  catch (e) {
182
198
  console.error(` ! Failed to re-parse the output of the slicer for ${JSON.stringify(criteria)}`); //, e
@@ -194,13 +210,16 @@ async function summarizeSlicerStats(stats, report = () => {
194
210
  return {
195
211
  ...stats,
196
212
  perSliceMeasurements: {
197
- numberOfSlices: perSliceStats.size,
213
+ numberOfSlices: stats.perSliceMeasurements.size,
198
214
  sliceCriteriaSizes: (0, summarizer_1.summarizeMeasurement)(sizeOfSliceCriteria),
199
215
  measurements: summarized,
200
216
  failedToRepParse: failedOutputs,
201
217
  timesHitThreshold,
202
218
  reduction: summarizeReductions(reductions),
203
219
  reductionNoFluff: summarizeReductions(reductionsNoFluff),
220
+ sliceTimePerToken: summarizeTimePerToken(sliceTimes),
221
+ reconstructTimePerToken: summarizeTimePerToken(reconstructTimes),
222
+ totalPerSliceTimePerToken: summarizeTimePerToken(totalTimes),
204
223
  sliceSize: {
205
224
  lines: (0, summarizer_1.summarizeMeasurement)(sliceSize.lines),
206
225
  nonEmptyLines: (0, summarizer_1.summarizeMeasurement)(sliceSize.nonEmptyLines),
@@ -220,6 +239,7 @@ async function summarizeSlicerStats(stats, report = () => {
220
239
  }
221
240
  exports.summarizeSlicerStats = summarizeSlicerStats;
222
241
  function summarizeSummarizedMeasurement(data) {
242
+ data = data.filter(assert_1.isNotUndefined);
223
243
  const min = data.map(d => d.min).filter(assert_1.isNotUndefined).reduce((a, b) => Math.min(a, b), Infinity);
224
244
  const max = data.map(d => d.max).filter(assert_1.isNotUndefined).reduce((a, b) => Math.max(a, b), -Infinity);
225
245
  // calculate median of medians (don't just average the median!)
@@ -255,4 +275,18 @@ function summarizeReductions(reductions) {
255
275
  numberOfDataflowNodes: (0, summarizer_1.summarizeMeasurement)(reductions.map(r => r.numberOfDataflowNodes).filter(assert_1.isNotUndefined))
256
276
  };
257
277
  }
278
+ function summarizeSummarizedTimePerToken(times) {
279
+ return {
280
+ raw: summarizeSummarizedMeasurement(times.map(t => t.raw)),
281
+ normalized: summarizeSummarizedMeasurement(times.map(t => t.normalized)),
282
+ };
283
+ }
284
+ exports.summarizeSummarizedTimePerToken = summarizeSummarizedTimePerToken;
285
+ function summarizeTimePerToken(times) {
286
+ return {
287
+ raw: (0, summarizer_1.summarizeMeasurement)(times.map(t => t.raw)),
288
+ normalized: (0, summarizer_1.summarizeMeasurement)(times.map(t => t.normalized)),
289
+ };
290
+ }
291
+ exports.summarizeTimePerToken = summarizeTimePerToken;
258
292
  //# sourceMappingURL=process.js.map
@@ -47,6 +47,13 @@ function writeGraphOutput(ultimate, outputGraphPath) {
47
47
  value: ultimate.reduction.numberOfNormalizedTokens.mean,
48
48
  extra: `std: ${ultimate.reduction.numberOfNormalizedTokens.std}`
49
49
  });
50
+ data.push({
51
+ name: 'memory (df-graph)',
52
+ unit: 'Bytes',
53
+ value: Number(ultimate.dataflow.sizeOfObject.mean),
54
+ range: Number(ultimate.dataflow.sizeOfObject.std),
55
+ extra: `median: ${(ultimate.dataflow.sizeOfObject.median).toFixed(2)}`
56
+ });
50
57
  // write the output file
51
58
  fs_1.default.writeFileSync(outputGraphPath, JSON.stringify(data, json_1.jsonReplacer));
52
59
  }
@@ -9,6 +9,14 @@ const stats_1 = require("../../stats/stats");
9
9
  function summarizeAllSummarizedStats(stats) {
10
10
  const commonMeasurements = new defaultmap_1.DefaultMap(() => []);
11
11
  const perSliceMeasurements = new defaultmap_1.DefaultMap(() => []);
12
+ const sliceTimesPerToken = [];
13
+ const reconstructTimesPerToken = [];
14
+ const totalPerSliceTimesPerToken = [];
15
+ const retrieveTimesPerToken = [];
16
+ const normalizeTimesPerToken = [];
17
+ const dataflowTimesPerToken = [];
18
+ const totalCommonTimesPerToken = [];
19
+ const memory = new defaultmap_1.DefaultMap(() => []);
12
20
  const reductions = [];
13
21
  const reductionsNoFluff = [];
14
22
  const inputs = [];
@@ -23,6 +31,16 @@ function summarizeAllSummarizedStats(stats) {
23
31
  for (const [k, v] of stat.perSliceMeasurements.measurements) {
24
32
  perSliceMeasurements.get(k).push(v);
25
33
  }
34
+ sliceTimesPerToken.push(stat.perSliceMeasurements.sliceTimePerToken);
35
+ reconstructTimesPerToken.push(stat.perSliceMeasurements.reconstructTimePerToken);
36
+ totalPerSliceTimesPerToken.push(stat.perSliceMeasurements.totalPerSliceTimePerToken);
37
+ retrieveTimesPerToken.push(stat.retrieveTimePerToken);
38
+ normalizeTimesPerToken.push(stat.normalizeTimePerToken);
39
+ dataflowTimesPerToken.push(stat.dataflowTimePerToken);
40
+ totalCommonTimesPerToken.push(stat.totalCommonTimePerToken);
41
+ for (const [k, v] of stat.memory) {
42
+ memory.get(k).push(v);
43
+ }
26
44
  reductions.push(stat.perSliceMeasurements.reduction);
27
45
  reductionsNoFluff.push(stat.perSliceMeasurements.reductionNoFluff);
28
46
  inputs.push(stat.input);
@@ -36,6 +54,13 @@ function summarizeAllSummarizedStats(stats) {
36
54
  totalSlices: totalSlices,
37
55
  commonMeasurements: new Map([...commonMeasurements.entries()].map(([k, v]) => [k, (0, summarizer_1.summarizeMeasurement)(v)])),
38
56
  perSliceMeasurements: new Map([...perSliceMeasurements.entries()].map(([k, v]) => [k, (0, process_1.summarizeSummarizedMeasurement)(v)])),
57
+ sliceTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(sliceTimesPerToken),
58
+ reconstructTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(reconstructTimesPerToken),
59
+ totalPerSliceTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(totalPerSliceTimesPerToken),
60
+ retrieveTimePerToken: (0, process_1.summarizeTimePerToken)(retrieveTimesPerToken),
61
+ normalizeTimePerToken: (0, process_1.summarizeTimePerToken)(normalizeTimesPerToken),
62
+ dataflowTimePerToken: (0, process_1.summarizeTimePerToken)(dataflowTimesPerToken),
63
+ totalCommonTimePerToken: (0, process_1.summarizeTimePerToken)(totalCommonTimesPerToken),
39
64
  failedToRepParse,
40
65
  timesHitThreshold,
41
66
  reduction: (0, process_1.summarizeSummarizedReductions)(reductions),
@@ -56,7 +81,8 @@ function summarizeAllSummarizedStats(stats) {
56
81
  numberOfNodes: (0, summarizer_1.summarizeMeasurement)(dataflows.map(d => d.numberOfNodes)),
57
82
  numberOfFunctionDefinitions: (0, summarizer_1.summarizeMeasurement)(dataflows.map(d => d.numberOfFunctionDefinitions)),
58
83
  numberOfCalls: (0, summarizer_1.summarizeMeasurement)(dataflows.map(d => d.numberOfCalls)),
59
- numberOfEdges: (0, summarizer_1.summarizeMeasurement)(dataflows.map(d => d.numberOfEdges))
84
+ numberOfEdges: (0, summarizer_1.summarizeMeasurement)(dataflows.map(d => d.numberOfEdges)),
85
+ sizeOfObject: (0, summarizer_1.summarizeMeasurement)(dataflows.map(d => d.sizeOfObject))
60
86
  }
61
87
  };
62
88
  }
@@ -71,6 +97,13 @@ function summarizeAllUltimateStats(stats) {
71
97
  // average out / summarize other measurements
72
98
  commonMeasurements: new Map(stats_1.CommonSlicerMeasurements.map(m => [m, (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.commonMeasurements.get(m)))])),
73
99
  perSliceMeasurements: new Map(stats_1.PerSliceMeasurements.map(m => [m, (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.perSliceMeasurements.get(m)))])),
100
+ sliceTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.sliceTimePerToken)),
101
+ reconstructTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.reconstructTimePerToken)),
102
+ totalPerSliceTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.totalPerSliceTimePerToken)),
103
+ retrieveTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.retrieveTimePerToken)),
104
+ normalizeTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.normalizeTimePerToken)),
105
+ dataflowTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.dataflowTimePerToken)),
106
+ totalCommonTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.totalCommonTimePerToken)),
74
107
  reduction: (0, process_1.summarizeSummarizedReductions)(stats.map(s => s.reduction)),
75
108
  reductionNoFluff: (0, process_1.summarizeSummarizedReductions)(stats.map(s => s.reductionNoFluff)),
76
109
  input: {
@@ -89,7 +122,8 @@ function summarizeAllUltimateStats(stats) {
89
122
  numberOfNodes: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataflow.numberOfNodes)),
90
123
  numberOfFunctionDefinitions: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataflow.numberOfFunctionDefinitions)),
91
124
  numberOfCalls: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataflow.numberOfCalls)),
92
- numberOfEdges: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataflow.numberOfEdges))
125
+ numberOfEdges: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataflow.numberOfEdges)),
126
+ sizeOfObject: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataflow.sizeOfObject))
93
127
  }
94
128
  };
95
129
  }
@@ -98,23 +132,19 @@ function processNextSummary(line, allSummarized) {
98
132
  let got = JSON.parse(line.toString());
99
133
  got = {
100
134
  summarize: {
101
- input: got.summarize.input,
102
- request: got.summarize.request,
103
- dataflow: got.summarize.dataflow,
135
+ ...got.summarize,
136
+ // restore maps
137
+ memory: new Map(got.summarize.memory
138
+ .map(([k, v]) => [k, v])),
104
139
  commonMeasurements: new Map(got.summarize.commonMeasurements
105
140
  .map(([k, v]) => {
106
141
  (0, assert_1.guard)(v.endsWith('n'), 'Expected a bigint');
107
142
  return [k, BigInt(v.slice(0, -1))];
108
143
  })),
109
144
  perSliceMeasurements: {
110
- numberOfSlices: got.summarize.perSliceMeasurements.numberOfSlices,
111
- sliceCriteriaSizes: got.summarize.perSliceMeasurements.sliceCriteriaSizes,
145
+ ...got.summarize.perSliceMeasurements,
146
+ // restore maps
112
147
  measurements: new Map(got.summarize.perSliceMeasurements.measurements),
113
- reduction: got.summarize.perSliceMeasurements.reduction,
114
- reductionNoFluff: got.summarize.perSliceMeasurements.reductionNoFluff,
115
- timesHitThreshold: got.summarize.perSliceMeasurements.timesHitThreshold,
116
- failedToRepParse: got.summarize.perSliceMeasurements.failedToRepParse,
117
- sliceSize: got.summarize.perSliceMeasurements.sliceSize
118
148
  }
119
149
  }
120
150
  };
@@ -124,20 +154,12 @@ exports.processNextSummary = processNextSummary;
124
154
  function processNextUltimateSummary(line, allSummarized) {
125
155
  let got = JSON.parse(line.toString());
126
156
  got = {
127
- summarize: {
128
- totalRequests: got.summarize.totalRequests,
129
- totalSlices: got.summarize.totalSlices,
130
- commonMeasurements: new Map(got.summarize.commonMeasurements),
131
- perSliceMeasurements: new Map(got.summarize.perSliceMeasurements),
132
- failedToRepParse: got.summarize.failedToRepParse,
133
- timesHitThreshold: got.summarize.timesHitThreshold,
134
- reduction: got.summarize.reduction,
135
- reductionNoFluff: got.summarize.reductionNoFluff,
136
- input: got.summarize.input,
137
- dataflow: got.summarize.dataflow,
138
- }
157
+ ...got,
158
+ // restore maps
159
+ commonMeasurements: new Map(got.commonMeasurements),
160
+ perSliceMeasurements: new Map(got.perSliceMeasurements),
139
161
  };
140
- allSummarized.push(got.summarize);
162
+ allSummarized.push(got);
141
163
  }
142
164
  exports.processNextUltimateSummary = processNextUltimateSummary;
143
165
  //# sourceMappingURL=process.js.map
@@ -28,4 +28,5 @@ export declare class BenchmarkSummarizer extends Summarizer<UltimateSlicerStats,
28
28
  preparationPhase(): Promise<void>;
29
29
  summarizePhase(): Promise<UltimateSlicerStats>;
30
30
  private removeIfExists;
31
+ private summaryFile;
31
32
  }
@@ -13,31 +13,41 @@ const summarizer_1 = require("../../util/summarizer");
13
13
  const files_1 = require("../../util/files");
14
14
  const json_1 = require("../../util/json");
15
15
  const print_1 = require("../stats/print");
16
+ const defaultmap_1 = require("../../util/defaultmap");
16
17
  class BenchmarkSummarizer extends summarizer_1.Summarizer {
17
18
  constructor(config) {
18
19
  super(config);
19
20
  }
20
21
  async preparationPhase() {
21
- this.removeIfExists(`${this.config.intermediateOutputPath}.json`);
22
+ this.removeIfExists(this.summaryFile());
22
23
  this.removeIfExists(this.config.intermediateOutputPath);
23
24
  fs_1.default.mkdirSync(this.config.intermediateOutputPath);
24
- const dirContent = fs_1.default.readdirSync(this.config.inputPath);
25
- for (let i = 0; i < dirContent.length; i++) {
26
- const filePath = path_1.default.join(this.config.inputPath, dirContent[i]);
27
- const outputPath = path_1.default.join(this.config.intermediateOutputPath, dirContent[i]);
25
+ const filesToSummarize = fs_1.default.readdirSync(this.config.inputPath);
26
+ const outputPathsPerRun = new defaultmap_1.DefaultMap(() => []);
27
+ for (let i = 0; i < filesToSummarize.length; i++) {
28
+ const fileInputPath = path_1.default.join(this.config.inputPath, filesToSummarize[i]);
29
+ const outputDir = path_1.default.join(this.config.intermediateOutputPath, path_1.default.parse(filesToSummarize[i]).name);
30
+ fs_1.default.mkdirSync(outputDir);
31
+ const textOutputPath = path_1.default.join(outputDir, 'summary.log');
28
32
  // generate measurements for each run
29
- await (0, files_1.readLineByLine)(filePath, (line, lineNumber) => (0, input_1.processRunMeasurement)(line, i, lineNumber, `${outputPath}.log`, outputPath));
30
- // generate combined measurements for the file
31
- (0, input_1.processSummarizedFileMeasurement)(filePath, outputPath, `${this.config.intermediateOutputPath}.json`);
33
+ await (0, files_1.readLineByLine)(fileInputPath, (line, lineNumber) => {
34
+ const runOutputPath = path_1.default.join(outputDir, `run-${lineNumber}.json`);
35
+ outputPathsPerRun.get(lineNumber).push(runOutputPath);
36
+ return (0, input_1.processRunMeasurement)(line, i, lineNumber, textOutputPath, runOutputPath);
37
+ });
38
+ }
39
+ // generate combined measurements for each file per run
40
+ for (const [run, paths] of outputPathsPerRun.entries()) {
41
+ (0, input_1.processSummarizedRunMeasurement)(run, paths, this.summaryFile());
32
42
  }
33
43
  this.log('Done summarizing');
34
44
  }
35
45
  // eslint-disable-next-line @typescript-eslint/require-await -- just to obey the structure
36
46
  async summarizePhase() {
37
- this.log(`Summarizing all summaries from ${this.config.inputPath}...`);
47
+ this.log(`Summarizing all summaries from ${this.summaryFile()}...`);
38
48
  this.removeIfExists(this.config.outputPath);
39
49
  const summaries = [];
40
- (0, files_1.readLineByLineSync)(`${this.config.intermediateOutputPath}.json`, (l) => (0, process_1.processNextUltimateSummary)(l, summaries));
50
+ (0, files_1.readLineByLineSync)(this.summaryFile(), (l) => (0, process_1.processNextUltimateSummary)(l, summaries));
41
51
  const ultimate = (0, process_1.summarizeAllUltimateStats)(summaries);
42
52
  this.log(`Writing ultimate summary to ${this.config.outputPath}`);
43
53
  fs_1.default.writeFileSync(this.config.outputPath, JSON.stringify(ultimate, json_1.jsonReplacer));
@@ -53,6 +63,9 @@ class BenchmarkSummarizer extends summarizer_1.Summarizer {
53
63
  fs_1.default.rmSync(path, { recursive: true });
54
64
  }
55
65
  }
66
+ summaryFile() {
67
+ return `${this.config.intermediateOutputPath}.json`;
68
+ }
56
69
  }
57
70
  exports.BenchmarkSummarizer = BenchmarkSummarizer;
58
71
  //# sourceMappingURL=summarizer.js.map
@@ -9,6 +9,7 @@ import type { DataflowGraph } from '../graph/graph';
9
9
  import type { ControlDependency } from '../info';
10
10
  export declare function makeReferenceMaybe(ref: IdentifierReference, graph: DataflowGraph, environments: REnvironmentInformation, includeDefs: boolean, defaultCd?: ControlDependency | undefined): IdentifierReference;
11
11
  export declare function makeAllMaybe(references: readonly IdentifierReference[] | undefined, graph: DataflowGraph, environments: REnvironmentInformation, includeDefs: boolean, defaultCd?: ControlDependency | undefined): IdentifierReference[];
12
+ export type EnvironmentMemory = Map<Identifier, IdentifierDefinition[]>;
12
13
  export interface IEnvironment {
13
14
  /** unique and internally generated identifier -- will not be used for comparison but assists debugging for tracking identities */
14
15
  readonly id: string;
@@ -17,7 +18,7 @@ export interface IEnvironment {
17
18
  /**
18
19
  * Maps to exactly one definition of an identifier if the source is known, otherwise to a list of all possible definitions
19
20
  */
20
- memory: Map<Identifier, IdentifierDefinition[]>;
21
+ memory: EnvironmentMemory;
21
22
  }
22
23
  export declare class Environment implements IEnvironment {
23
24
  readonly id: string;
@@ -2,7 +2,6 @@
2
2
  * An edge consist of:
3
3
  * - the target node (i.e., the variable or processing node),
4
4
  * - a type (if it is read or used in the context), and
5
- * - an attribute (if this edge exists for every program execution or if it is only one possible execution path).
6
5
  */
7
6
  export interface DataflowGraphEdge {
8
7
  types: EdgeTypeBits;
@@ -40,8 +39,8 @@ export declare const enum EdgeTypeName {
40
39
  DefinedBy = "defined-by",
41
40
  Calls = "calls",
42
41
  Returns = "returns",
43
- DefinesOnCall = "defined-by-on-call",
44
- DefinedByOnCall = "defines-on-call",
42
+ DefinesOnCall = "defines-on-call",
43
+ DefinedByOnCall = "defined-by-on-call",
45
44
  Argument = "argument",
46
45
  SideEffectOnCall = "side-effect-on-call",
47
46
  NonStandardEvaluation = "non-standard-evaluation"
@@ -6,8 +6,8 @@ const edgeTypeToHumanReadableName = new Map([
6
6
  [2 /* EdgeType.DefinedBy */, "defined-by" /* EdgeTypeName.DefinedBy */],
7
7
  [4 /* EdgeType.Calls */, "calls" /* EdgeTypeName.Calls */],
8
8
  [8 /* EdgeType.Returns */, "returns" /* EdgeTypeName.Returns */],
9
- [16 /* EdgeType.DefinesOnCall */, "defined-by-on-call" /* EdgeTypeName.DefinesOnCall */],
10
- [32 /* EdgeType.DefinedByOnCall */, "defines-on-call" /* EdgeTypeName.DefinedByOnCall */],
9
+ [16 /* EdgeType.DefinesOnCall */, "defines-on-call" /* EdgeTypeName.DefinesOnCall */],
10
+ [32 /* EdgeType.DefinedByOnCall */, "defined-by-on-call" /* EdgeTypeName.DefinedByOnCall */],
11
11
  [64 /* EdgeType.Argument */, "argument" /* EdgeTypeName.Argument */],
12
12
  [128 /* EdgeType.SideEffectOnCall */, "side-effect-on-call" /* EdgeTypeName.SideEffectOnCall */],
13
13
  [256 /* EdgeType.NonStandardEvaluation */, "non-standard-evaluation" /* EdgeTypeName.NonStandardEvaluation */]
@@ -7,6 +7,7 @@ const arrays_1 = require("../../util/arrays");
7
7
  const r_function_call_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
8
8
  const environment_1 = require("../environments/environment");
9
9
  const clone_1 = require("../environments/clone");
10
+ const built_in_1 = require("../environments/built-in");
10
11
  function isPositionalArgument(arg) {
11
12
  return arg !== r_function_call_1.EmptyArgument && arg.name === undefined;
12
13
  }
@@ -159,7 +160,6 @@ class DataflowGraph {
159
160
  const environment = vertex.environment === undefined ? fallback : (0, clone_1.cloneEnvironmentInformation)(vertex.environment);
160
161
  this.vertexInformation.set(vertex.id, {
161
162
  ...vertex,
162
- when: vertex.controlDependencies ?? 'always',
163
163
  environment
164
164
  });
165
165
  if (asRoot) {
@@ -171,11 +171,12 @@ class DataflowGraph {
171
171
  * Will insert a new edge into the graph,
172
172
  * if the direction of the edge is of no importance (`same-read-read` or `same-def-def`), source
173
173
  * and target will be sorted so that `from` has the lower, and `to` the higher id (default ordering).
174
+ * Please note, that this will never make edges to {@link BuiltIn} as they are not part of the graph.
174
175
  */
175
176
  addEdge(from, to, edgeInfo) {
176
177
  const { fromId, toId } = extractEdgeIds(from, to);
177
178
  const { type, ...rest } = edgeInfo;
178
- if (fromId === toId) {
179
+ if (fromId === toId || toId === built_in_1.BuiltIn) {
179
180
  return this;
180
181
  }
181
182
  /* we now that we pass all required arguments */
@@ -11,7 +11,6 @@ function processValue(value, data) {
11
11
  graph: new graph_1.DataflowGraph(data.completeAst.idMap).addVertex({
12
12
  tag: "value" /* VertexType.Value */,
13
13
  id: value.info.id,
14
- value: value.lexeme,
15
14
  controlDependencies: data.controlDependencies
16
15
  }),
17
16
  exitPoints: [{ nodeId: value.info.id, type: 0 /* ExitPointType.Default */, controlDependencies: data.controlDependencies }],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eagleoutice/flowr",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "Static Dataflow Analyzer and Program Slicer for the R Programming Language",
5
5
  "types": "dist/src/index.d.ts",
6
6
  "repository": {
@@ -228,6 +228,7 @@
228
228
  "n-readlines": "^1.0.1",
229
229
  "n3": "^1.17.2",
230
230
  "object-hash": "^3.0.0",
231
+ "object-sizeof": "^2.6.4",
231
232
  "rotating-file-stream": "^3.1.1",
232
233
  "semver": "^7.5.4",
233
234
  "tar": "^7.1.0",
@@ -7,7 +7,6 @@ type Mark = MarkVertex | MarkEdge;
7
7
  interface MermaidGraph {
8
8
  nodeLines: string[];
9
9
  edgeLines: string[];
10
- hasBuiltIn: boolean;
11
10
  includeEnvironments: boolean;
12
11
  mark: ReadonlySet<Mark> | undefined;
13
12
  /** in the form of from-\>to because I am lazy, see {@link encodeEdge} */
@@ -7,7 +7,6 @@ const graph_1 = require("../../dataflow/graph/graph");
7
7
  const r_function_call_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
8
8
  const edge_1 = require("../../dataflow/graph/edge");
9
9
  const environment_1 = require("../../dataflow/environments/environment");
10
- const built_in_1 = require("../../dataflow/environments/built-in");
11
10
  function formatRange(range) {
12
11
  if (range === undefined) {
13
12
  return '??-??';
@@ -151,9 +150,6 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark) {
151
150
  if (edgeTypes.has('CD-True')) {
152
151
  mermaid.edgeLines.push(` linkStyle ${mermaid.presentEdges.size - 1} stroke:gray,color:gray;`);
153
152
  }
154
- if (target === built_in_1.BuiltIn) {
155
- mermaid.hasBuiltIn = true;
156
- }
157
153
  }
158
154
  }
159
155
  if (info.tag === 'function-definition') {
@@ -162,15 +158,12 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark) {
162
158
  }
163
159
  // make the passing of root ids more performant again
164
160
  function graphToMermaidGraph(rootIds, { graph, prefix = 'flowchart TD', idPrefix = '', includeEnvironments = true, mark, rootGraph, presentEdges = new Set() }) {
165
- const mermaid = { nodeLines: prefix === null ? [] : [prefix], edgeLines: [], presentEdges, hasBuiltIn: false, mark, rootGraph: rootGraph ?? graph, includeEnvironments };
161
+ const mermaid = { nodeLines: prefix === null ? [] : [prefix], edgeLines: [], presentEdges, mark, rootGraph: rootGraph ?? graph, includeEnvironments };
166
162
  for (const [id, info] of graph.vertices(true)) {
167
163
  if (rootIds.has(id)) {
168
164
  vertexToMermaid(info, mermaid, id, idPrefix, mark);
169
165
  }
170
166
  }
171
- if (mermaid.hasBuiltIn) {
172
- mermaid.nodeLines.push(` ${idPrefix}${built_in_1.BuiltIn}["Built-in"]`);
173
- }
174
167
  return mermaid;
175
168
  }
176
169
  function graphToMermaid(config) {
package/util/version.js CHANGED
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.flowrVersion = void 0;
4
4
  const semver_1 = require("semver");
5
5
  // this is automatically replaced with the current version by release-it
6
- const version = '2.0.2';
6
+ const version = '2.0.4';
7
7
  function flowrVersion() {
8
8
  return new semver_1.SemVer(version);
9
9
  }