cli: support ${pid} placeholder in --cpu-prof-name

PR-URL: https://github.com/nodejs/node/pull/59072
Fixes: https://github.com/nodejs/node/issues/57418
Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Haram Jeong 2025-07-24 19:28:18 +09:00 committed by GitHub
parent 38c2b926af
commit 7215d9b37f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 66 additions and 4 deletions

View file

@ -538,13 +538,16 @@ $ ls *.cpuprofile
CPU.20190409.202950.15293.0.0.cpuprofile
```
If `--cpu-prof-name` is specified, the provided value will be used as-is; patterns such as
`${hhmmss}` or `${pid}` are not supported.
If `--cpu-prof-name` is specified, the provided value is used as a template
for the file name. The following placeholder is supported and will be
substituted at runtime:
* `${pid}` — the current process ID
```console
$ node --cpu-prof --cpu-prof-name 'CPU.${pid}.cpuprofile' index.js
$ ls *.cpuprofile
'CPU.${pid}.cpuprofile'
CPU.15293.cpuprofile
```
### `--cpu-prof-dir`

View file

@ -8,6 +8,7 @@
#include "node_file.h"
#include "node_internals.h"
#include "util-inl.h"
#include "uv.h"
#include "v8-inspector.h"
#include <cinttypes>
@ -465,6 +466,27 @@ static void EndStartedProfilers(Environment* env) {
}
}
static std::string ReplacePlaceholders(const std::string& pattern) {
std::string result = pattern;
static const std::unordered_map<std::string, std::function<std::string()>>
kPlaceholderMap = {
{"${pid}", []() { return std::to_string(uv_os_getpid()); }},
// TODO(haramj): Add more placeholders as needed.
};
for (const auto& [placeholder, getter] : kPlaceholderMap) {
size_t pos = 0;
while ((pos = result.find(placeholder, pos)) != std::string::npos) {
const std::string value = getter();
result.replace(pos, placeholder.length(), value);
pos += value.length();
}
}
return result;
}
void StartProfilers(Environment* env) {
AtExit(env, [](void* env) {
EndStartedProfilers(static_cast<Environment*>(env));
@ -486,7 +508,9 @@ void StartProfilers(Environment* env) {
DiagnosticFilename filename(env, "CPU", "cpuprofile");
env->set_cpu_prof_name(*filename);
} else {
env->set_cpu_prof_name(env->options()->cpu_prof_name);
std::string resolved_name =
ReplacePlaceholders(env->options()->cpu_prof_name);
env->set_cpu_prof_name(resolved_name);
}
CHECK_NULL(env->cpu_profiler_connection());
env->set_cpu_profiler_connection(

View file

@ -8,6 +8,8 @@ const fixtures = require('../common/fixtures');
common.skipIfInspectorDisabled();
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const { spawnSync } = require('child_process');
const tmpdir = require('../common/tmpdir');
@ -41,3 +43,36 @@ const {
assert.deepStrictEqual(profiles, [file]);
verifyFrames(output, file, 'fibonacci.js');
}
// --cpu-prof-name with ${pid} placeholder
{
tmpdir.refresh();
// eslint-disable-next-line no-template-curly-in-string
const profName = 'CPU.${pid}.cpuprofile';
const dir = tmpdir.path;
const output = spawnSync(process.execPath, [
'--cpu-prof',
'--cpu-prof-interval',
kCpuProfInterval,
'--cpu-prof-name',
profName,
fixtures.path('workload', 'fibonacci.js'),
], {
cwd: dir,
env
});
if (output.status !== 0) {
console.error(output.stderr.toString());
}
assert.strictEqual(output.status, 0);
const expectedFile = path.join(dir, `CPU.${output.pid}.cpuprofile`);
assert.ok(fs.existsSync(expectedFile), `Expected file ${expectedFile} not found.`);
verifyFrames(output, expectedFile, 'fibonacci.js');
fs.unlinkSync(expectedFile);
}