MCPcopy Index your code
hub / github.com/parse-community/parse-server / measureMemoryOperation

Function measureMemoryOperation

benchmark/performance.js:214–303  ·  view source on GitHub ↗

* Measure GC pressure for an async operation over multiple iterations. * Tracks total garbage collection time per operation using PerformanceObserver. * Using total GC time (sum of all pauses) rather than max single pause provides * much more stable metrics — it eliminates the variance from V8 ch

({ name, operation, iterations, skipWarmup = false })

Source from the content-addressed store, hash-verified

212 * @param {boolean} [options.skipWarmup=false] Skip warmup phase.
213 */
214async function measureMemoryOperation({ name, operation, iterations, skipWarmup = false }) {
215 const { PerformanceObserver } = require('node:perf_hooks');
216
217 // Override iterations if global ITERATIONS is set
218 iterations = ITERATIONS || iterations;
219
220 // Determine warmup count (20% of iterations)
221 const warmupCount = skipWarmup ? 0 : Math.floor(iterations * 0.2);
222 const gcDurations = [];
223
224 if (warmupCount > 0) {
225 logInfo(`Starting warmup phase of ${warmupCount} iterations...`);
226 for (let i = 0; i < warmupCount; i++) {
227 await operation();
228 }
229 logInfo('Warmup complete.');
230 }
231
232 // Measurement phase
233 logInfo(`Starting measurement phase of ${iterations} iterations...`);
234 const progressInterval = Math.ceil(iterations / 10);
235
236 for (let i = 0; i < iterations; i++) {
237 // Force GC before each iteration to start from a clean state
238 if (typeof global.gc === 'function') {
239 global.gc();
240 }
241
242 // Track GC events during this iteration; sum all GC pause durations to
243 // measure total GC work, which is stable regardless of whether V8 chooses
244 // one long pause or many short pauses
245 let totalGcTime = 0;
246 const obs = new PerformanceObserver((list) => {
247 for (const entry of list.getEntries()) {
248 totalGcTime += entry.duration;
249 }
250 });
251 obs.observe({ type: 'gc', buffered: false });
252
253 await operation();
254
255 // Force GC after the operation to flush pending GC work into this
256 // iteration's measurement, preventing cross-iteration contamination
257 if (typeof global.gc === 'function') {
258 global.gc();
259 }
260
261 // Flush any buffered entries before disconnecting to avoid data loss
262 for (const entry of obs.takeRecords()) {
263 totalGcTime += entry.duration;
264 }
265 obs.disconnect();
266 gcDurations.push(totalGcTime);
267
268 if (LOG_ITERATIONS) {
269 logInfo(`Iteration ${i + 1}: ${totalGcTime.toFixed(2)} ms GC`);
270 } else if ((i + 1) % progressInterval === 0 || i + 1 === iterations) {
271 const progress = Math.round(((i + 1) / iterations) * 100);

Callers 2

Calls 2

logInfoFunction · 0.85
filterMethod · 0.80

Tested by

no test coverage detected