@@ -14,6 +14,7 @@ import { fork } from 'node:child_process';
1414import { setTimeout } from 'node:timers/promises' ;
1515import { fileURLToPath } from 'node:url' ;
1616import { dirname , join } from 'node:path' ;
17+ import * as fs from 'node:fs/promises' ;
1718
1819const __filename = fileURLToPath ( import . meta. url ) ;
1920const __dirname = dirname ( __filename ) ;
@@ -22,6 +23,35 @@ const SAMPLE_COUNT = 3; // Number of samples to measure
2223const STARTUP_TIMEOUT = 120000 ; // 120 seconds timeout for server startup
2324const MEMORY_SETTLE_TIME = 10000 ; // Wait 10 seconds after startup for memory to settle
2425
26+ const keys = {
27+ VmPeak : 0 ,
28+ VmSize : 0 ,
29+ VmHWM : 0 ,
30+ VmRSS : 0 ,
31+ VmData : 0 ,
32+ VmStk : 0 ,
33+ VmExe : 0 ,
34+ VmLib : 0 ,
35+ VmPTE : 0 ,
36+ VmSwap : 0 ,
37+ } ;
38+
39+ async function getMemoryUsage ( pid ) {
40+ const status = await fs . readFile ( `/proc/${ pid } /status` , 'utf-8' ) ;
41+
42+ const result = { } ;
43+ for ( const key of Object . keys ( keys ) ) {
44+ const match = status . match ( new RegExp ( `${ key } :\\s+(\\d+)\\s+kB` ) ) ;
45+ if ( match ) {
46+ result [ key ] = parseInt ( match [ 1 ] , 10 ) ;
47+ } else {
48+ throw new Error ( `Failed to parse ${ key } from /proc/${ pid } /status` ) ;
49+ }
50+ }
51+
52+ return result ;
53+ }
54+
2555async function measureMemory ( ) {
2656 // Start the Misskey backend server using fork to enable IPC
2757 const serverProcess = fork ( join ( __dirname , '../built/boot/entry.js' ) , [ 'expose-gc' ] , {
@@ -76,39 +106,7 @@ async function measureMemory() {
76106
77107 // Get memory usage from the server process via /proc
78108 const pid = serverProcess . pid ;
79- let memoryInfo ;
80-
81- try {
82- const fs = await import ( 'node:fs/promises' ) ;
83-
84- // Read /proc/[pid]/status for detailed memory info
85- const status = await fs . readFile ( `/proc/${ pid } /status` , 'utf-8' ) ;
86- const vmRssMatch = status . match ( / V m R S S : \s + ( \d + ) \s + k B / ) ;
87- const vmDataMatch = status . match ( / V m D a t a : \s + ( \d + ) \s + k B / ) ;
88- const vmSizeMatch = status . match ( / V m S i z e : \s + ( \d + ) \s + k B / ) ;
89-
90- memoryInfo = {
91- rss : vmRssMatch ? parseInt ( vmRssMatch [ 1 ] , 10 ) * 1024 : null ,
92- heapUsed : vmDataMatch ? parseInt ( vmDataMatch [ 1 ] , 10 ) * 1024 : null ,
93- vmSize : vmSizeMatch ? parseInt ( vmSizeMatch [ 1 ] , 10 ) * 1024 : null ,
94- } ;
95- } catch ( err ) {
96- // Fallback: use ps command
97- process . stderr . write ( `Warning: Could not read /proc/${ pid } /status: ${ err } \n` ) ;
98-
99- const { execSync } = await import ( 'node:child_process' ) ;
100- try {
101- const ps = execSync ( `ps -o rss= -p ${ pid } ` , { encoding : 'utf-8' } ) ;
102- const rssKb = parseInt ( ps . trim ( ) , 10 ) ;
103- memoryInfo = {
104- rss : rssKb * 1024 ,
105- heapUsed : null ,
106- vmSize : null ,
107- } ;
108- } catch {
109- throw new Error ( 'Failed to get memory usage via ps command' ) ;
110- }
111- }
109+ const memoryInfo = await getMemoryUsage ( pid ) ;
112110
113111 // Stop the server
114112 serverProcess . kill ( 'SIGTERM' ) ;
@@ -146,19 +144,15 @@ async function main() {
146144 }
147145
148146 // Calculate averages
149- const avgMemory = {
150- rss : 0 ,
151- heapUsed : 0 ,
152- vmSize : 0 ,
153- } ;
147+ const avgMemory = structuredClone ( keys ) ;
154148 for ( const res of results ) {
155- avgMemory . rss += res . memory . rss ?? 0 ;
156- avgMemory . heapUsed += res . memory . heapUsed ?? 0 ;
157- avgMemory . vmSize += res . memory . vmSize ?? 0 ;
149+ for ( const key of Object . keys ( avgMemory ) ) {
150+ avgMemory [ key ] += res . memory [ key ] ;
151+ }
152+ }
153+ for ( const key of Object . keys ( avgMemory ) ) {
154+ avgMemory [ key ] = Math . round ( avgMemory [ key ] / SAMPLE_COUNT ) ;
158155 }
159- avgMemory . rss = Math . round ( avgMemory . rss / SAMPLE_COUNT ) ;
160- avgMemory . heapUsed = Math . round ( avgMemory . heapUsed / SAMPLE_COUNT ) ;
161- avgMemory . vmSize = Math . round ( avgMemory . vmSize / SAMPLE_COUNT ) ;
162156
163157 const result = {
164158 timestamp : new Date ( ) . toISOString ( ) ,
0 commit comments