From bbfcdf21e507b91968f9fc72746e9fce2941a687 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Wed, 16 Oct 2024 08:05:46 -0400 Subject: [PATCH] add garbage collection to async resource map --- async-interceptor.js | 30 ++++++++++++++++++++++-------- save-output.js | 4 ++-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/async-interceptor.js b/async-interceptor.js index 8f210ab..646ae87 100644 --- a/async-interceptor.js +++ b/async-interceptor.js @@ -1,25 +1,39 @@ import async_hooks from 'node:async_hooks'; -export const asyncResources = new Map(); +// 50% of map limit +export const GC_LIMIT = Math.pow(2, 23); + +export const AsyncResourceMap = new Map(); export const AsyncInterceptor = async_hooks.createHook({ - init(asyncId, type, triggerAsyncId, resource) { - logResourceCreation(asyncId, type, triggerAsyncId, resource); + init(asyncId, type) { + logResourceCreation(asyncId, type); }, }); -function logResourceCreation(asyncId, type, triggerAsyncId, resource) { +function logResourceCreation(asyncId, type) { const stack = (new Error()).stack.split('\n').slice(2).filter(line => { return !['AsyncHook.init', 'node:internal/async_hooks'].some(fn => line.includes(fn)); }).join('\n'); - if (!asyncResources.has(stack)) { - asyncResources.set(stack, { count: 0, types: new Set() }); + if (AsyncResourceMap.size > GC_LIMIT) { + console.log('Meteor Perf: Garbage collecting async resources'); + garbageCollectAsyncResources(); + } + + if (!AsyncResourceMap.has(stack)) { + AsyncResourceMap.set(stack, { count: 0, types: new Set() }); } - const resourceInfo = asyncResources.get(stack); + const resourceInfo = AsyncResourceMap.get(stack); resourceInfo.count++; resourceInfo.types.add(type); } - +function garbageCollectAsyncResources() { + AsyncResourceMap.forEach((info, stack) => { + if (info.count <= 1) { + AsyncResourceMap.delete(stack); + } + }); +} \ No newline at end of file diff --git a/save-output.js b/save-output.js index 793319d..14a20f6 100644 --- a/save-output.js +++ b/save-output.js @@ -1,4 +1,4 @@ -import { asyncResources } from './async-interceptor'; +import { AsyncResourceMap } from './async-interceptor'; import { StatDict } from './observer-monitor'; import path from 'node:path'; import fs from 'node:fs'; @@ -9,7 +9,7 @@ export function saveOutput() { performance.mark('saveOutput-start'); let async_traces = [] - asyncResources.forEach((info, stack) => { + AsyncResourceMap.forEach((info, stack) => { if (info.count <= 1) { return; }