@torrent-tv/proxy 2.97.1 → 2.97.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -721,10 +721,14 @@ export class EncodeRun {
|
|
|
721
721
|
this.#stopping = true;
|
|
722
722
|
this.#stopReason = because;
|
|
723
723
|
this.#stopOrderedAt = this.now();
|
|
724
|
-
this.#transition(ENCODE_RUN_EVENT.STOP_ORDERED);
|
|
725
724
|
// A suspended process does not act on SIGTERM until it is continued, so the
|
|
726
|
-
// wait for its exit would never end. Let it run before asking it to stop
|
|
725
|
+
// wait for its exit would never end. Let it run before asking it to stop —
|
|
726
|
+
// and before the state leaves SUSPENDED, because the state is what
|
|
727
|
+
// `#continue` reads. Field 2026-10-11: the order was the other way round,
|
|
728
|
+
// no SIGCONT was sent, and a stopped soundtrack encoder stayed in state `T`
|
|
729
|
+
// with its 75 MB input admitted for as long as the process lived.
|
|
727
730
|
this.#continue();
|
|
731
|
+
this.#transition(ENCODE_RUN_EVENT.STOP_ORDERED);
|
|
728
732
|
this.#signal("SIGTERM");
|
|
729
733
|
}
|
|
730
734
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* process figure alone is said.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import {
|
|
19
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
20
20
|
|
|
21
21
|
/** Clock ticks per second of `/proc/<pid>/stat`, as in `encode/host-load.js`. */
|
|
22
22
|
const CLOCK_TICKS_PER_SECOND = 100;
|
|
@@ -58,26 +58,46 @@ export function partOfThread(tid, name, pid) {
|
|
|
58
58
|
return "other";
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* One `/proc` stat file, or null when it cannot be read.
|
|
63
|
+
*
|
|
64
|
+
* @param {string} file
|
|
65
|
+
* @returns {{ name: string, seconds: number } | null}
|
|
66
|
+
*/
|
|
67
|
+
function statOf(file) {
|
|
68
|
+
try {
|
|
69
|
+
return parseStat(readFileSync(file, "utf8"));
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
61
75
|
/**
|
|
62
76
|
* CPU seconds of this process's threads, by part, or null where `/proc` cannot
|
|
63
77
|
* be read.
|
|
64
78
|
*
|
|
79
|
+
* READ SYNCHRONOUSLY, with the clock read beside it: a reading is only a share
|
|
80
|
+
* when every counter in it and its time belong to one instant. Read as
|
|
81
|
+
* promises on the field host (2.97.0), the counters were taken while the main
|
|
82
|
+
* thread was busy and the time after, and a second read "process 1238 %" of a
|
|
83
|
+
* core (torrent-tv/meta#177). About a hundred small files a second, kernel
|
|
84
|
+
* memory, no disk.
|
|
85
|
+
*
|
|
65
86
|
* @param {number} [pid]
|
|
66
|
-
* @returns {
|
|
87
|
+
* @returns {{ main: number, worker: number, other: number } | null}
|
|
67
88
|
*/
|
|
68
|
-
export
|
|
89
|
+
export function readThreadSeconds(pid = process.pid) {
|
|
69
90
|
let tids;
|
|
70
91
|
try {
|
|
71
|
-
tids =
|
|
92
|
+
tids = readdirSync(`/proc/${pid}/task`);
|
|
72
93
|
} catch {
|
|
73
94
|
return null;
|
|
74
95
|
}
|
|
75
96
|
const parts = { main: 0, worker: 0, other: 0 };
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}));
|
|
97
|
+
for (const entry of tids) {
|
|
98
|
+
const stat = statOf(`/proc/${pid}/task/${entry}/stat`);
|
|
99
|
+
if (stat) parts[partOfThread(Number(entry), stat.name, pid)] += stat.seconds;
|
|
100
|
+
}
|
|
81
101
|
return parts;
|
|
82
102
|
}
|
|
83
103
|
|
|
@@ -85,14 +105,14 @@ export async function readThreadSeconds(pid = process.pid) {
|
|
|
85
105
|
* CPU seconds of each of these processes that can be read now.
|
|
86
106
|
*
|
|
87
107
|
* @param {number[]} pids
|
|
88
|
-
* @returns {
|
|
108
|
+
* @returns {Map<number, number>}
|
|
89
109
|
*/
|
|
90
|
-
export
|
|
110
|
+
export function readProcessesSeconds(pids) {
|
|
91
111
|
const seconds = new Map();
|
|
92
|
-
|
|
93
|
-
const stat =
|
|
112
|
+
for (const pid of pids) {
|
|
113
|
+
const stat = statOf(`/proc/${pid}/stat`);
|
|
94
114
|
if (stat) seconds.set(pid, stat.seconds);
|
|
95
|
-
}
|
|
115
|
+
}
|
|
96
116
|
return seconds;
|
|
97
117
|
}
|
|
98
118
|
|
|
@@ -158,29 +178,22 @@ export function startProcessorReport({ log, ffmpegPids, detailed = () => false,
|
|
|
158
178
|
let previous = null;
|
|
159
179
|
let series = [];
|
|
160
180
|
let since = Date.now();
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
series
|
|
173
|
-
|
|
174
|
-
if (now.at - since >= sayEveryMs) {
|
|
175
|
-
log(`processor: ${describeShares(series)}`);
|
|
176
|
-
series = [];
|
|
177
|
-
since = now.at;
|
|
178
|
-
}
|
|
179
|
-
} finally {
|
|
180
|
-
reading = false;
|
|
181
|
+
const tick = () => {
|
|
182
|
+
const at = Date.now();
|
|
183
|
+
const usage = process.cpuUsage();
|
|
184
|
+
const now = { at, process: (usage.user + usage.system) / 1e6, threads: readThreadSeconds(), ffmpeg: readProcessesSeconds(ffmpegPids()) };
|
|
185
|
+
const shares = previous ? sharesBetween(previous, now) : null;
|
|
186
|
+
previous = now;
|
|
187
|
+
if (!shares) return;
|
|
188
|
+
series.push(shares);
|
|
189
|
+
if (detailed()) log(`processor: ${describeShares([shares])}`);
|
|
190
|
+
if (now.at - since >= sayEveryMs) {
|
|
191
|
+
log(`processor: ${describeShares(series)}`);
|
|
192
|
+
series = [];
|
|
193
|
+
since = now.at;
|
|
181
194
|
}
|
|
182
195
|
};
|
|
183
|
-
const timer = setInterval(
|
|
196
|
+
const timer = setInterval(tick, everyMs);
|
|
184
197
|
if (typeof timer.unref === "function") timer.unref();
|
|
185
198
|
return { stop: () => clearInterval(timer) };
|
|
186
199
|
}
|