




















@@ -653,7 +653,7 @@ export async function sampleProcess(pid, options = {}) {
653653if (platform === "win32") {
654654return sampleWindowsProcess(pid, run, options.windowsCommandLineNeedles);
655655}
656-return samplePosixProcess(pid, run);
656+return samplePosixProcess(pid, run, options.posixCommandLineNeedles);
657657}
658658659659export function summarizeProcessSamples(samples) {
@@ -675,7 +675,13 @@ export function summarizeProcessSamples(samples) {
675675};
676676}
677677678-async function samplePosixProcess(pid, run) {
678+async function samplePosixProcess(pid, run, commandLineNeedles = []) {
679+const needles = commandLineNeedles
680+.map((needle) => String(needle ?? "").trim())
681+.filter((needle) => needle.length > 0);
682+if (needles.length > 0) {
683+return samplePosixProcessTree(pid, run, needles);
684+}
679685try {
680686const { stdout } = await run("ps", ["-o", "rss=,pcpu=", "-p", String(pid)], {
681687timeoutMs: 5000,
@@ -695,6 +701,106 @@ async function samplePosixProcess(pid, run) {
695701}
696702}
697703704+async function samplePosixProcessTree(pid, run, commandLineNeedles) {
705+const safePid = Number(pid);
706+if (!Number.isInteger(safePid) || safePid <= 0) {
707+return null;
708+}
709+try {
710+const { stdout } = await run("ps", ["-axo", "pid=,ppid=,rss=,pcpu=,command="], {
711+timeoutMs: 5000,
712+});
713+const rows = parsePosixProcessRows(stdout);
714+const descendants = collectPosixProcessTree(rows, safePid).filter(
715+(row) => row.processId !== safePid,
716+);
717+const commandMatches = descendants.filter((row) =>
718+commandLineNeedles.every((needle) =>
719+row.command.toLowerCase().includes(needle.toLowerCase()),
720+),
721+);
722+const gatewayTitleMatches = descendants.filter((row) =>
723+row.command.toLowerCase().includes("openclaw-gateway"),
724+);
725+const selected = selectPeakRssProcess(
726+commandMatches.length > 0
727+ ? commandMatches
728+ : gatewayTitleMatches.length > 0
729+ ? gatewayTitleMatches
730+ : descendants,
731+);
732+if (!selected) {
733+return null;
734+}
735+return formatPosixProcessSample(selected);
736+} catch {
737+return null;
738+}
739+}
740+741+function parsePosixProcessRows(stdout) {
742+return stdout
743+.split(/\r?\n/u)
744+.map((line) => {
745+const match = line.match(/^\s*(\d+)\s+(\d+)\s+(\d+)\s+([0-9.]+)\s+(.*)$/u);
746+if (!match) {
747+return null;
748+}
749+const [, pidRaw, ppidRaw, rssKbRaw, cpuRaw, command] = match;
750+const processId = Number.parseInt(pidRaw, 10);
751+const parentProcessId = Number.parseInt(ppidRaw, 10);
752+const rssKb = Number.parseInt(rssKbRaw, 10);
753+const cpuPercent = Number.parseFloat(cpuRaw);
754+if (
755+!Number.isInteger(processId) ||
756+!Number.isInteger(parentProcessId) ||
757+!Number.isFinite(rssKb)
758+) {
759+return null;
760+}
761+return {
762+ processId,
763+ parentProcessId,
764+ rssKb,
765+cpuPercent: Number.isFinite(cpuPercent) ? cpuPercent : null,
766+command: command ?? "",
767+};
768+})
769+.filter(Boolean);
770+}
771+772+function collectPosixProcessTree(rows, rootPid) {
773+const byParent = new Map();
774+for (const row of rows) {
775+const children = byParent.get(row.parentProcessId) ?? [];
776+children.push(row);
777+byParent.set(row.parentProcessId, children);
778+}
779+const root = rows.find((row) => row.processId === rootPid);
780+const collected = root ? [root] : [];
781+const pending = [rootPid];
782+while (pending.length > 0) {
783+const nextPid = pending.shift();
784+for (const child of byParent.get(nextPid) ?? []) {
785+collected.push(child);
786+pending.push(child.processId);
787+}
788+}
789+return collected;
790+}
791+792+function selectPeakRssProcess(rows) {
793+return rows.reduce((peak, row) => (peak && peak.rssKb >= row.rssKb ? peak : row), null);
794+}
795+796+function formatPosixProcessSample(row) {
797+return {
798+rssMiB: Math.round((row.rssKb / 1024) * 10) / 10,
799+cpuPercent: row.cpuPercent,
800+processId: row.processId,
801+};
802+}
803+698804function parseTasklistCsvLine(line) {
699805const values = [];
700806let current = "";
@@ -930,10 +1036,14 @@ export async function main() {
93010369311037child = await startGateway(runner, port, env, logPath);
9321038const sampleGateway = async () => {
933-const windowsSampleOptions = runner.pnpm
934- ? { windowsCommandLineNeedles: ["gateway", "--port", String(port)] }
1039+const gatewayCommandLineNeedles = ["gateway", "--port", String(port)];
1040+const processSampleOptions = runner.pnpm
1041+ ? {
1042+posixCommandLineNeedles: gatewayCommandLineNeedles,
1043+windowsCommandLineNeedles: gatewayCommandLineNeedles,
1044+}
9351045 : {};
936-let sample = await sampleProcess(child.pid, windowsSampleOptions);
1046+let sample = await sampleProcess(child.pid, processSampleOptions);
9371047if (!sample && process.platform === "win32") {
9381048sample = await sampleWindowsProcessByPort(port);
9391049}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。