@torrent-tv/proxy 2.101.5 → 2.101.6

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@torrent-tv/proxy",
3
- "version": "2.101.5",
3
+ "version": "2.101.6",
4
4
  "description": "Torrent proxy client that exposes webseed-like HTTP stream endpoint.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": {
@@ -160,9 +160,16 @@ export class PauseRule {
160
160
  const since = this.#triedAt.get(run) ?? Number.NEGATIVE_INFINITY;
161
161
  const beside = lead.filter((second) => second.running.has(run) && second.at > since);
162
162
  if (beside.length < LEAST_SECONDS) {
163
- // Let go by this rule and not measured yet: it runs until it is.
164
- // Running since before anything could be compared: the urgency rule.
165
- return this.#triedAt.has(run) ? { runs: true, because: `being measured beside the leader (${beside.length}s so far)` } : null;
163
+ if (this.#triedAt.has(run)) {
164
+ // Let go by this rule and not measured yet: it runs until it is.
165
+ return { runs: true, because: `being measured beside the leader (${beside.length}s so far)` };
166
+ }
167
+ // Running and not measured yet without having been let go by this rule
168
+ // (a start the plan made, or a run that led before): judged as a try,
169
+ // the condition `wouldStart` let it start under. Paused at once and
170
+ // tried a tick later instead, short runs on Home Assistant (r80) went
171
+ // through both: 81 pauses of 0.3 s (median), one per run.
172
+ return this.#whetherToTry({ leader, band, run, need, lead, without, draw, free, others, otherRunning, now });
166
173
  }
167
174
  const besideSpeed = middleAndScatter(beside.map((second) => second.speed));
168
175
  if (Number.isFinite(need)) {
@@ -157,7 +157,7 @@ export class HostLoad {
157
157
  #supplyByKey = new Map();
158
158
 
159
159
  /**
160
- * @param {object} host - `liveRunsOf`, `runStateOf`, the readings of `encode/host-load.js` (`readMachineState`, `readProcessCpuSeconds`, `readProxyCpuSeconds`, `readSystemCpu`, `shareOfMachine`), `getSourceStats`, `getTorrentTotals`, `outputs`
160
+ * @param {object} host - `liveRunsOf`, `runStateOf`, the readings of `encode/host-load.js` (`readMachineState`, `readProcessCpuSeconds`, `readProxyCpuSeconds`, `readSystemCpu`, `shareOfMachine`), `getSourceStats`, `getTorrentTotals`, `outputs`, and optionally `costSecOf(session)`, `EncodeCost`'s cost of an output, said beside each run's `k`
161
161
  */
162
162
  /** The share of the machine this process draws doing nothing priced; zero until measured. */
163
163
  get baseDraw() {
@@ -634,6 +634,13 @@ export class HostLoad {
634
634
  * Only runs read at both ends that made film in between are said. For the
635
635
  * log only.
636
636
  *
637
+ * Beside each `k`, `EncodeCost`'s cost of the run's output (`c`) and `k`
638
+ * converted to that unit over the cores this process may use (`k/U`), on the
639
+ * same reading: where a run uses less than it is given the two differ, and
640
+ * whether the processor claim moves from `c` to `k` is judged from these
641
+ * lines (plan 2.3, torrent-tv/meta#180). `c` is filed as if the run were
642
+ * alone on a quiet machine; a `k` read beside other runs is not.
643
+ *
637
644
  * @param {{ takenAt: number, byPid: Map<number, number>, runs?: Map<number, { film: number | null, label: string, kind: string }> }} previous
638
645
  * @param {{ takenAt: number, byPid: Map<number, number>, runs?: Map<number, { film: number | null, label: string, kind: string }> }} sample
639
646
  */
@@ -642,6 +649,8 @@ export class HostLoad {
642
649
  const elapsedSec = (sample.takenAt - previous.takenAt) / 1000;
643
650
  if (!(elapsedSec > 0)) return;
644
651
  const alive = new Map([...previous.runs, ...sample.runs]);
652
+ const boundCores = Number(sample.processor?.bound?.cores);
653
+ const cores = Number.isFinite(boundCores) && boundCores > 0 ? boundCores : Math.max(1, os.cpus().length);
645
654
  const said = [];
646
655
  for (const [pid, run] of sample.runs) {
647
656
  const before = previous.runs.get(pid);
@@ -653,15 +662,34 @@ export class HostLoad {
653
662
  if (!(film > 0)) continue;
654
663
  const cpu = cpuNow - cpuBefore;
655
664
  const beside = [...alive].filter(([other]) => other !== pid).map(([, other]) => other.kind);
656
- said.push(`${run.label} ${run.kind} k=${(cpu / film).toFixed(3)} CPU-s per film-s ` +
665
+ const k = cpu / film;
666
+ said.push(`${run.label} ${run.kind} k=${k.toFixed(3)} CPU-s per film-s ` +
657
667
  `(${cpu.toFixed(2)} CPU-s, ${film.toFixed(2)} film-s, speed ${(film / elapsedSec).toFixed(2)}x, ` +
658
- `${(cpu / elapsedSec).toFixed(2)} cores), beside ${beside.length}` + (beside.length > 0 ? ` [${beside.join(", ")}]` : ""));
668
+ `${(cpu / elapsedSec).toFixed(2)} cores), ` +
669
+ `c=${Number.isFinite(run.costSec) && run.costSec > 0 ? run.costSec.toFixed(3) : "unpriced"} k/U=${(k / cores).toFixed(3)} ` +
670
+ `(U=${cores.toFixed(2)} cores), beside ${beside.length}` + (beside.length > 0 ? ` [${beside.join(", ")}]` : ""));
659
671
  }
660
672
  if (said.length > 0) {
661
673
  logger.info(`processor: run cost over ${elapsedSec.toFixed(1)}s: ${said.join("; ")}`);
662
674
  }
663
675
  }
664
676
 
677
+ /**
678
+ * `EncodeCost`'s cost of an output, for the log; null where it is unpriced
679
+ * or cannot be read.
680
+ *
681
+ * @param {object} session
682
+ * @returns {number | null}
683
+ */
684
+ #costSecOf(session) {
685
+ try {
686
+ const cost = Number(this.#host.costSecOf?.(session));
687
+ return Number.isFinite(cost) && cost > 0 ? cost : null;
688
+ } catch {
689
+ return null;
690
+ }
691
+ }
692
+
665
693
  /**
666
694
  * @param {{ elapsedSec: number, processShare: number | null, systemShare: number | null, rejected?: string[] } | null} share
667
695
  * @param {{ proxyCpuSeconds: number | null }} previous
@@ -750,7 +778,8 @@ export class HostLoad {
750
778
  startedAt: run.startedAt,
751
779
  film: filmMadeBy(run),
752
780
  label: `${session.outputKey ?? session.id} #${run.from}..#${run.to}`,
753
- kind: costKindForSession(session)
781
+ kind: costKindForSession(session),
782
+ costSec: this.#costSecOf(session)
754
783
  })));
755
784
  const [system, endedChildren, ...cpuReadings] = await Promise.all([
756
785
  this.#host.readSystemCpu(),
@@ -761,7 +790,7 @@ export class HostLoad {
761
790
  const byPid = new Map();
762
791
  /** @type {Map<number, number>} */
763
792
  const startedAt = new Map();
764
- /** @type {Map<number, { film: number | null, label: string, kind: string }>} */
793
+ /** @type {Map<number, { film: number | null, label: string, kind: string, costSec: number | null }>} */
765
794
  const runsByPid = new Map();
766
795
  runs.forEach((run, index) => {
767
796
  const seconds = cpuReadings[index];
@@ -769,7 +798,7 @@ export class HostLoad {
769
798
  byPid.set(run.pid, seconds);
770
799
  startedAt.set(run.pid, run.startedAt);
771
800
  }
772
- runsByPid.set(run.pid, { film: run.film, label: run.label, kind: run.kind });
801
+ runsByPid.set(run.pid, { film: run.film, label: run.label, kind: run.kind, costSec: run.costSec });
773
802
  });
774
803
  const sample = {
775
804
  takenAt: Date.now(),
@@ -309,6 +309,8 @@ export function wireOutputs({
309
309
  describeProcessor,
310
310
  liveRunsOf: (...args) => parts.encodeRuns.liveRunsOf(...args),
311
311
  runStateOf: (...args) => parts.encodeRuns.runStateOf(...args),
312
+ // Today's cost `c` beside each run's measured `k` (torrent-tv/meta#180, plan 2.3).
313
+ costSecOf: (session) => parts.encodeCost?.loadOfOutput(session.outputKey)?.costSec ?? null,
312
314
  get getSourceStats() { return parts.getSourceStats; },
313
315
  get getTorrentTotals() { return parts.getTorrentTotals; },
314
316
  get outputs() { return parts.outputs; },