

























@@ -2,14 +2,20 @@
22import { spawn, spawnSync, type ChildProcessWithoutNullStreams } from "node:child_process";
33import fs from "node:fs";
44import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
5-import { request } from "node:http";
6-import { createServer } from "node:net";
75import { tmpdir } from "node:os";
86import path from "node:path";
97import { performance } from "node:perf_hooks";
108import { pathToFileURL } from "node:url";
119import { parseStrictIntegerOption } from "./lib/dev-tooling-safety.ts";
1210import { delay, stopChild, type StopChildResult } from "./lib/gateway-bench-child.ts";
11+import {
12+classifyProbeErrorKind,
13+getFreePort,
14+parseProcessRssKb,
15+readProcessRssMb,
16+readProcessTreeCpuMs,
17+requestProbeStatus,
18+} from "./lib/gateway-bench-probes.ts";
13191420type GatewayBenchCase = {
1521config: Record<string, unknown>;
@@ -562,22 +568,6 @@ function summarizeCase(benchCase: GatewayBenchCase, samples: GatewayRestartSampl
562568};
563569}
564570565-async function getFreePort(): Promise<number> {
566-return new Promise((resolve, reject) => {
567-const server = createServer();
568-server.on("error", reject);
569-server.listen(0, "127.0.0.1", () => {
570-const address = server.address();
571-if (!address || typeof address === "string") {
572-server.close(() => reject(new Error("failed to allocate port")));
573-return;
574-}
575-const { port } = address;
576-server.close(() => resolve(port));
577-});
578-});
579-}
580-581571async function waitForProbeReady(params: {
582572deadlineAt: number;
583573isDone?: () => boolean;
@@ -727,59 +717,6 @@ async function waitForRestartProbe(params: {
727717};
728718}
729719730-async function requestProbeStatus(
731-port: number,
732-pathname: string,
733-): Promise<{ errorKind: string | null; status: number | null }> {
734-try {
735-const status = await requestStatus(port, pathname);
736-return {
737-errorKind: status === 200 ? null : `http-${status}`,
738- status,
739-};
740-} catch (error) {
741-return {
742-errorKind: classifyProbeErrorKind(error),
743-status: null,
744-};
745-}
746-}
747-748-function classifyProbeErrorKind(error: unknown): string {
749-if (typeof error === "object" && error !== null) {
750-const code = (error as { code?: unknown }).code;
751-if (typeof code === "string" && code.trim()) {
752-return code.trim().toLowerCase();
753-}
754-const message = (error as { message?: unknown }).message;
755-if (typeof message === "string" && message.toLowerCase().includes("probe timeout")) {
756-return "timeout";
757-}
758-const name = (error as { name?: unknown }).name;
759-if (typeof name === "string" && name.trim()) {
760-return name.trim().toLowerCase();
761-}
762-}
763-return "error";
764-}
765-766-function requestStatus(port: number, pathname: string): Promise<number> {
767-return new Promise((resolve, reject) => {
768-const req = request(
769-{ host: "127.0.0.1", method: "GET", path: pathname, port, timeout: 100 },
770-(res) => {
771-res.resume();
772-res.on("end", () => resolve(res.statusCode ?? 0));
773-},
774-);
775-req.on("error", reject);
776-req.on("timeout", () => {
777-req.destroy(new Error("probe timeout"));
778-});
779-req.end();
780-});
781-}
782-783720function writePluginFixtures(
784721root: string,
785722count: number,
@@ -888,30 +825,6 @@ function writeRestartIntent(env: NodeJS.ProcessEnv, targetPid: number, reason: s
888825}
889826}
890827891-function readProcessRssMb(pid: number | undefined): number | null {
892-if (!pid || process.platform === "win32") {
893-return null;
894-}
895-const result = spawnSync("ps", ["-o", "rss=", "-p", String(pid)], {
896-encoding: "utf8",
897-stdio: ["ignore", "pipe", "ignore"],
898-});
899-if (result.status !== 0) {
900-return null;
901-}
902-const rssKb = parseProcessRssKb(result.stdout);
903-return rssKb === null ? null : rssKb / 1024;
904-}
905-906-function parseProcessRssKb(raw: string): number | null {
907-const value = raw.trim();
908-if (!/^[1-9][0-9]*$/u.test(value)) {
909-return null;
910-}
911-const rssKb = Number(value);
912-return Number.isSafeInteger(rssKb) ? rssKb : null;
913-}
914-915828function readProcessFdCount(pid: number | undefined): number | null {
916829if (!pid || process.platform === "win32") {
917830return null;
@@ -948,71 +861,6 @@ function countLsofFileDescriptors(raw: string): number | null {
948861return count;
949862}
950863951-function parsePsCpuTimeMs(raw: string): number | null {
952-const parts = raw.trim().split(":").map(Number);
953-if (parts.some((part) => !Number.isFinite(part) || part < 0)) {
954-return null;
955-}
956-if (parts.length === 2) {
957-return Math.round((parts[0] * 60 + parts[1]) * 1000);
958-}
959-if (parts.length === 3) {
960-return Math.round((parts[0] * 60 * 60 + parts[1] * 60 + parts[2]) * 1000);
961-}
962-return null;
963-}
964-965-function readProcessTreeCpuMs(rootPid: number | undefined): number | null {
966-if (!rootPid || process.platform === "win32") {
967-return null;
968-}
969-const result = spawnSync("ps", ["-eo", "pid=,ppid=,time="], {
970-encoding: "utf8",
971-stdio: ["ignore", "pipe", "ignore"],
972-});
973-if (result.status !== 0) {
974-return null;
975-}
976-977-const childrenByParent = new Map<number, number[]>();
978-const cpuByPid = new Map<number, number>();
979-for (const line of result.stdout.split("\n")) {
980-const match = line.trim().match(/^(\d+)\s+(\d+)\s+(\S+)$/u);
981-if (!match) {
982-continue;
983-}
984-const pid = Number(match[1]);
985-const ppid = Number(match[2]);
986-const cpuMs = parsePsCpuTimeMs(match[3]);
987-if (!Number.isInteger(pid) || !Number.isInteger(ppid) || cpuMs === null) {
988-continue;
989-}
990-cpuByPid.set(pid, cpuMs);
991-const children = childrenByParent.get(ppid) ?? [];
992-children.push(pid);
993-childrenByParent.set(ppid, children);
994-}
995-if (!cpuByPid.has(rootPid)) {
996-return null;
997-}
998-999-let totalCpuMs = 0;
1000-const seen = new Set<number>();
1001-const stack = [rootPid];
1002-while (stack.length > 0) {
1003-const pid = stack.pop();
1004-if (!pid || seen.has(pid)) {
1005-continue;
1006-}
1007-seen.add(pid);
1008-totalCpuMs += cpuByPid.get(pid) ?? 0;
1009-for (const childPid of childrenByParent.get(pid) ?? []) {
1010-stack.push(childPid);
1011-}
1012-}
1013-return totalCpuMs;
1014-}
1015-1016864function snapshotResources(
1017865child: ChildProcessWithoutNullStreams,
1018866sampleStartAt: number,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。