@ai-ecoverse/slicc-kernel 1.66.1 → 1.67.0

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.
@@ -7108,11 +7108,11 @@ var ChildTable = class {
7108
7108
  return [...this.children.keys()];
7109
7109
  }
7110
7110
  captured(pid, slot2) {
7111
- const slots = this.leftovers.get(pid);
7112
- const chunks = slots?.get(slot2);
7113
- if (!slots || !chunks) return new Uint8Array(0);
7114
- slots.delete(slot2);
7115
- if (slots.size === 0) this.leftovers.delete(pid);
7111
+ const slots2 = this.leftovers.get(pid);
7112
+ const chunks = slots2?.get(slot2);
7113
+ if (!slots2 || !chunks) return new Uint8Array(0);
7114
+ slots2.delete(slot2);
7115
+ if (slots2.size === 0) this.leftovers.delete(pid);
7116
7116
  return concat3(chunks);
7117
7117
  }
7118
7118
  };
@@ -8584,7 +8584,9 @@ async function dispatchOne(entry, req) {
8584
8584
 
8585
8585
  // src/realm/sync-sab-wire.ts
8586
8586
  var SAB_HEADER_I32 = 16;
8587
- var SAB_HEADER_BYTES = SAB_HEADER_I32 * 4;
8587
+ var SAB_CLOCK_OFFSET = SAB_HEADER_I32 * 4;
8588
+ var SAB_CLOCK_I64 = 3;
8589
+ var SAB_HEADER_BYTES = SAB_CLOCK_OFFSET + SAB_CLOCK_I64 * 8;
8588
8590
  var SAB_I_STATE = 0;
8589
8591
  var SAB_I_SEQ = 1;
8590
8592
  var SAB_I_STATUS = 2;
@@ -8734,6 +8736,146 @@ function attachSyncSabResponder(port, sab, token, opts) {
8734
8736
  };
8735
8737
  }
8736
8738
 
8739
+ // src/kernel/cpu-clock.ts
8740
+ var IDLE_OPS = /* @__PURE__ */ new Set([
8741
+ "fd-select",
8742
+ "proc-wait",
8743
+ "proc-exec",
8744
+ "sig-pause",
8745
+ "sock-accept",
8746
+ "sock-connect"
8747
+ ]);
8748
+ var SYS_CAP_US = 2e4;
8749
+ var LOCAL = SAB_CLOCK_OFFSET;
8750
+ var IDLE = 1;
8751
+ function epochMicros() {
8752
+ return Math.floor((performance.timeOrigin + performance.now()) * 1e3);
8753
+ }
8754
+ function slots(sab) {
8755
+ return new BigInt64Array(sab, LOCAL, SAB_CLOCK_I64);
8756
+ }
8757
+ var rawWait = Atomics.wait.bind(Atomics);
8758
+ function localIdle(sab, now) {
8759
+ const state = Number(Atomics.load(slots(sab), IDLE));
8760
+ if (state >= 0) return { idle: state, waiting: false };
8761
+ return { idle: Math.max(0, now + state), waiting: true };
8762
+ }
8763
+ var CpuClock = class {
8764
+ start;
8765
+ sys = 0;
8766
+ idle = 0;
8767
+ since = 0;
8768
+ kind = "sys";
8769
+ stopped = false;
8770
+ last = { utime: 0, stime: 0 };
8771
+ sab;
8772
+ now;
8773
+ constructor(sab, now = epochMicros) {
8774
+ this.sab = sab;
8775
+ this.now = now;
8776
+ this.start = now();
8777
+ }
8778
+ enter(op) {
8779
+ this.since = this.now();
8780
+ this.kind = this.stopped || IDLE_OPS.has(op) ? "idle" : "sys";
8781
+ }
8782
+ leave() {
8783
+ if (this.since === 0) return;
8784
+ this.add((this.frozen ?? this.now()) - this.since);
8785
+ this.since = 0;
8786
+ }
8787
+ stop(stopped) {
8788
+ if (stopped === this.stopped) return;
8789
+ this.stopped = stopped;
8790
+ if (this.since === 0 || !stopped || this.frozen !== void 0) return;
8791
+ const now = this.now();
8792
+ this.add(now - this.since);
8793
+ this.since = now;
8794
+ this.kind = "idle";
8795
+ }
8796
+ frozen;
8797
+ freeze() {
8798
+ this.frozen ??= this.now();
8799
+ }
8800
+ running() {
8801
+ if (this.frozen !== void 0) return false;
8802
+ const now = this.now();
8803
+ const busy = this.since === 0 || this.kind === "sys" && now - this.since < SYS_CAP_US;
8804
+ return busy && !localIdle(this.sab, now).waiting;
8805
+ }
8806
+ times() {
8807
+ const now = this.frozen ?? this.now();
8808
+ const open = this.since === 0 ? 0 : Math.max(0, now - this.since);
8809
+ const busy = this.kind === "sys" ? Math.min(open, SYS_CAP_US) : 0;
8810
+ const sys = this.sys + busy;
8811
+ const idle = this.idle + (open - busy) + localIdle(this.sab, now).idle;
8812
+ const user = Math.max(0, now - this.start - sys - idle);
8813
+ this.last = {
8814
+ utime: Math.max(this.last.utime, Math.floor(user / 1e3)),
8815
+ stime: Math.max(this.last.stime, Math.floor(sys / 1e3))
8816
+ };
8817
+ return this.last;
8818
+ }
8819
+ add(micros) {
8820
+ const spent = Math.max(0, micros);
8821
+ const busy = this.kind === "sys" ? Math.min(spent, SYS_CAP_US) : 0;
8822
+ this.sys += busy;
8823
+ this.idle += spent - busy;
8824
+ }
8825
+ };
8826
+ var ProcessClocks = class {
8827
+ main;
8828
+ threads = /* @__PURE__ */ new Map();
8829
+ ended = { utime: 0, stime: 0 };
8830
+ enabled;
8831
+ constructor(sab, enabled = true, states) {
8832
+ this.main = new CpuClock(sab);
8833
+ this.enabled = enabled;
8834
+ states?.onState((state) => this.stop(state === "stopped"));
8835
+ }
8836
+ thread(tid, sab) {
8837
+ const clock = new CpuClock(sab);
8838
+ this.threads.set(tid, clock);
8839
+ return clock;
8840
+ }
8841
+ threadEnded(tid) {
8842
+ const spent = this.threads.get(tid)?.times();
8843
+ this.threads.delete(tid);
8844
+ if (!spent) return;
8845
+ this.ended.utime += spent.utime;
8846
+ this.ended.stime += spent.stime;
8847
+ }
8848
+ stop(stopped) {
8849
+ for (const c of this.all()) c.stop(stopped);
8850
+ }
8851
+ freeze() {
8852
+ for (const c of this.all()) c.freeze();
8853
+ }
8854
+ times() {
8855
+ if (!this.enabled) return void 0;
8856
+ const sum = { ...this.ended };
8857
+ for (const c of this.all()) {
8858
+ const t = c.times();
8859
+ sum.utime += t.utime;
8860
+ sum.stime += t.stime;
8861
+ }
8862
+ return sum;
8863
+ }
8864
+ running() {
8865
+ return this.enabled ? this.all().filter((c) => c.running()).length : 0;
8866
+ }
8867
+ timed(clock, dispatch2) {
8868
+ const c = clock ?? this.main;
8869
+ return (req) => {
8870
+ c.enter(req.op);
8871
+ return dispatch2(req).finally(() => c.leave());
8872
+ };
8873
+ }
8874
+ all() {
8875
+ return [this.main, ...this.threads.values()];
8876
+ }
8877
+ };
8878
+
8737
8879
  // src/fs/pages.ts
8738
8880
  var PAGE = 64 * 1024;
8739
8881
  var READAHEAD = 1024 * 1024;
@@ -9018,8 +9160,8 @@ function pidStat(info, boot) {
9018
9160
  0,
9019
9161
  0,
9020
9162
  0,
9021
- 0,
9022
- 0,
9163
+ ticks(info.utime ?? 0),
9164
+ ticks(info.stime ?? 0),
9023
9165
  0,
9024
9166
  0,
9025
9167
  20,
@@ -9113,19 +9255,23 @@ function systemFile(name2, listing, now, memory) {
9113
9255
  if (name2 === "meminfo") {
9114
9256
  return memoryInfo(
9115
9257
  memory,
9116
- listing.processes.reduce((sum, p) => sum + p.memory, 0)
9258
+ listing.processes.reduce((sum2, p) => sum2 + p.memory, 0)
9117
9259
  );
9118
9260
  }
9119
9261
  const live = listing.processes.filter((p) => p.state !== "Z");
9120
9262
  if (name2 === "loadavg") {
9121
9263
  const last = Math.max(0, ...listing.processes.map((p) => p.pid));
9122
- return `0.00 0.00 0.00 1/${live.length} ${last}
9264
+ const [one, five, fifteen] = (listing.load ?? [0, 0, 0]).map((n) => n.toFixed(2));
9265
+ return `${one} ${five} ${fifteen} 1/${live.length} ${last}
9123
9266
  `;
9124
9267
  }
9125
- const idle = ticks(now - listing.boot);
9268
+ const sum = (key) => listing.cpu?.[key] ?? listing.processes.reduce((n, p) => n + (p[key] ?? 0), 0);
9269
+ const user = ticks(sum("utime"));
9270
+ const system = ticks(sum("stime"));
9271
+ const idle = listing.cpu ? ticks(listing.cpu.idle) : Math.max(0, ticks(now - listing.boot) - user - system);
9126
9272
  return [
9127
- `cpu 0 0 0 ${idle} 0 0 0 0 0 0`,
9128
- `cpu0 0 0 0 ${idle} 0 0 0 0 0 0`,
9273
+ `cpu ${user} 0 ${system} ${idle} 0 0 0 0 0 0`,
9274
+ `cpu0 ${user} 0 ${system} ${idle} 0 0 0 0 0 0`,
9129
9275
  "intr 0",
9130
9276
  "ctxt 0",
9131
9277
  `btime ${Math.floor(listing.boot / 1e3)}`,
@@ -12264,6 +12410,9 @@ function killThread(thread, caught, sig) {
12264
12410
  blocked.abort();
12265
12411
  return true;
12266
12412
  }
12413
+ function threadSignalsOf(sab) {
12414
+ return { header: new Int32Array(sab, 0, SAB_HEADER_I32), interrupt: new AbortController() };
12415
+ }
12267
12416
  function threadCancel(thread) {
12268
12417
  return Atomics.load(thread.header, SAB_I_SIGNALS) !== 0 ? AbortSignal.abort() : thread.interrupt.signal;
12269
12418
  }
@@ -12389,6 +12538,22 @@ function processOptions(opts, header3, hooks, created3) {
12389
12538
  ...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {}
12390
12539
  };
12391
12540
  }
12541
+ function threadInit(opts, program, sab, cred, thread) {
12542
+ return {
12543
+ type: WASM_THREAD_INIT,
12544
+ pid: opts.shownPid ?? opts.pid,
12545
+ program,
12546
+ argv0: opts.argv0,
12547
+ args: opts.args,
12548
+ env: opts.env,
12549
+ cwd: opts.cwd,
12550
+ sab,
12551
+ cred: copyCred(cred),
12552
+ owners: opts.owners === true,
12553
+ ...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
12554
+ thread
12555
+ };
12556
+ }
12392
12557
  function spawnWasmProcess(opts) {
12393
12558
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
12394
12559
  const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
@@ -12421,7 +12586,10 @@ function spawnWasmProcess(opts) {
12421
12586
  const worker = opts.createWorker();
12422
12587
  const dying = new Dying();
12423
12588
  const dispatch2 = (req) => dying.serving(() => isWasmSyscall(req) ? process.syscall(req) : dispatchSyncFs(req));
12424
- const responder = attachSyncSabResponder(worker, sab, token, { dispatch: dispatch2 });
12589
+ const clocks = new ProcessClocks(sab, opts.program.abi !== "js", process);
12590
+ const responder = attachSyncSabResponder(worker, sab, token, {
12591
+ dispatch: clocks.timed(void 0, dispatch2)
12592
+ });
12425
12593
  const lane = opts.program.abi === "js" ? openLane(token, dispatch2) : void 0;
12426
12594
  const { promise: exited, resolve: settle3 } = Promise.withResolvers();
12427
12595
  let done4 = false;
@@ -12429,6 +12597,7 @@ function spawnWasmProcess(opts) {
12429
12597
  const finish = (code, sig) => {
12430
12598
  if (done4) return;
12431
12599
  done4 = true;
12600
+ clocks.freeze();
12432
12601
  dying.clear();
12433
12602
  endedBy = sig ?? process.execTermsig;
12434
12603
  worker.removeEventListener("message", onMessage);
@@ -12469,6 +12638,7 @@ function spawnWasmProcess(opts) {
12469
12638
  const endThread = (tid) => {
12470
12639
  const end = threads.get(tid);
12471
12640
  threads.delete(tid);
12641
+ clocks.threadEnded(tid);
12472
12642
  process.threadEnded(tid);
12473
12643
  end?.();
12474
12644
  };
@@ -12482,15 +12652,14 @@ function spawnWasmProcess(opts) {
12482
12652
  }
12483
12653
  const tsab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
12484
12654
  const tw = opts.createWorker();
12485
- const tsignals = {
12486
- header: new Int32Array(tsab, 0, SAB_HEADER_I32),
12487
- interrupt: new AbortController()
12488
- };
12655
+ const tsignals = threadSignalsOf(tsab);
12489
12656
  threadSignals.set(thread.tid, tsignals);
12490
12657
  const tdispatch = (req) => dying.serving(
12491
12658
  () => isWasmSyscall(req) ? process.syscall(req, threadCancel(tsignals)) : dispatchSyncFs(req)
12492
12659
  );
12493
- const tresponder = attachSyncSabResponder(tw, tsab, token, { dispatch: tdispatch });
12660
+ const tresponder = attachSyncSabResponder(tw, tsab, token, {
12661
+ dispatch: clocks.timed(clocks.thread(thread.tid, tsab), tdispatch)
12662
+ });
12494
12663
  const onThreadMessage = (event) => {
12495
12664
  const data = event.data;
12496
12665
  if (data?.type === WASM_THREAD_EXIT) endThread(thread.tid);
@@ -12505,21 +12674,7 @@ function spawnWasmProcess(opts) {
12505
12674
  tresponder.dispose();
12506
12675
  tw.terminate();
12507
12676
  });
12508
- const tinit = {
12509
- type: WASM_THREAD_INIT,
12510
- pid: opts.shownPid ?? opts.pid,
12511
- program,
12512
- argv0: opts.argv0,
12513
- args: opts.args,
12514
- env: opts.env,
12515
- cwd: opts.cwd,
12516
- sab: tsab,
12517
- cred: copyCred(process.cred),
12518
- owners: opts.owners === true,
12519
- ...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
12520
- thread
12521
- };
12522
- tw.postMessage(tinit);
12677
+ tw.postMessage(threadInit(opts, program, tsab, process.cred, thread));
12523
12678
  };
12524
12679
  worker.postMessage(
12525
12680
  processInit(opts, sab, process.umask, copyCred(process.cred), lane?.lane),
@@ -12544,7 +12699,9 @@ function spawnWasmProcess(opts) {
12544
12699
  signalMasks: () => process.signalMasks(),
12545
12700
  umask: () => process.umask,
12546
12701
  cred: () => copyCred(process.cred),
12547
- writesBack: () => opts.program.abi === "wasi" && !done4
12702
+ writesBack: () => opts.program.abi === "wasi" && !done4,
12703
+ times: () => clocks.times(),
12704
+ running: () => clocks.running()
12548
12705
  };
12549
12706
  }
12550
12707
 
@@ -14860,6 +15017,8 @@ var LAYOUT = [
14860
15017
  ["/usr", 493],
14861
15018
  ["/usr/local", 493]
14862
15019
  ];
15020
+ var LOAD_SAMPLE_MS = 5e3;
15021
+ var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
14863
15022
  var encoder3 = new TextEncoder();
14864
15023
  var USERS_MODES = ["off", "report", "enforce"];
14865
15024
  function usersMode(mode = "off") {
@@ -15388,6 +15547,7 @@ var Launcher = class {
15388
15547
  return this.jobs.sessionOf(pgid);
15389
15548
  }
15390
15549
  start(req) {
15550
+ this.sampling();
15391
15551
  if (req.pgid !== void 0 && this.jobs.sessionOf(req.pgid) === void 0) {
15392
15552
  throw fsError("ESRCH", `no process group ${req.pgid}`);
15393
15553
  }
@@ -15428,7 +15588,12 @@ var Launcher = class {
15428
15588
  forker: this.forker(pid, req),
15429
15589
  kill: (target, sig) => this.kill(target, sig, this.credOf(pid), pid),
15430
15590
  writesBack: (target) => this.processes.get(target)?.writesBack() === true,
15431
- processes: () => ({ boot: this.boot, processes: this.list(this.credOf(pid)) }),
15591
+ processes: () => ({
15592
+ boot: this.boot,
15593
+ processes: this.list(this.credOf(pid)),
15594
+ load: this.loadAverage(),
15595
+ cpu: this.cpuTotal()
15596
+ }),
15432
15597
  sudo: (call, signal) => this.sudo(pid, call, signal),
15433
15598
  openFiles: this.openFiles,
15434
15599
  nodes: this.nodes,
@@ -15462,7 +15627,14 @@ var Launcher = class {
15462
15627
  started: Date.now()
15463
15628
  });
15464
15629
  void handle.exited.then(() => {
15630
+ const spent = handle.times?.();
15631
+ if (spent) this.spent.set(pid, spent);
15465
15632
  this.processes.delete(pid);
15633
+ if (this.processes.size === 0) {
15634
+ clearInterval(this.sampler);
15635
+ this.sampler = void 0;
15636
+ this.idleSince = Date.now();
15637
+ }
15466
15638
  this.settling.settled(pid);
15467
15639
  if (req.ppid === void 0 || this.orphans.delete(pid)) this.forget(pid);
15468
15640
  else this.zombies.add(pid);
@@ -15478,6 +15650,12 @@ var Launcher = class {
15478
15650
  forget(pid) {
15479
15651
  this.jobs.remove(pid);
15480
15652
  this.described.delete(pid);
15653
+ const spent = this.spent.get(pid);
15654
+ if (spent) {
15655
+ this.reapedTimes.utime += spent.utime;
15656
+ this.reapedTimes.stime += spent.stime;
15657
+ }
15658
+ this.spent.delete(pid);
15481
15659
  this.creds.delete(pid);
15482
15660
  this.tags.delete(pid);
15483
15661
  this.granted.delete(pid);
@@ -15486,6 +15664,70 @@ var Launcher = class {
15486
15664
  if (this.zombies.delete(pid)) this.forget(pid);
15487
15665
  else this.orphans.add(pid);
15488
15666
  }
15667
+ load = [0, 0, 0];
15668
+ sampler;
15669
+ reapedTimes = { utime: 0, stime: 0 };
15670
+ idleAt = { wall: this.boot, busy: 0, idle: 0 };
15671
+ cpuTotal(now = Date.now()) {
15672
+ const total = { ...this.reapedTimes };
15673
+ const add = (t) => {
15674
+ total.utime += t?.utime ?? 0;
15675
+ total.stime += t?.stime ?? 0;
15676
+ };
15677
+ for (const handle of this.processes.values()) add(handle.times?.());
15678
+ for (const t of this.spent.values()) add(t);
15679
+ const busy = total.utime + total.stime;
15680
+ const at = this.idleAt;
15681
+ at.idle += Math.max(0, now - at.wall - (busy - at.busy));
15682
+ at.wall = Math.max(at.wall, now);
15683
+ at.busy = Math.max(at.busy, busy);
15684
+ return { ...total, idle: at.idle };
15685
+ }
15686
+ loadAverage() {
15687
+ return this.load;
15688
+ }
15689
+ sampledAt = Date.now();
15690
+ sampleLoad(now = Date.now()) {
15691
+ let running = 0;
15692
+ for (const handle of this.processes.values()) running += handle.running?.() ?? 0;
15693
+ const elapsed = Math.max(LOAD_SAMPLE_MS, now - this.sampledAt);
15694
+ this.sampledAt = Math.max(this.sampledAt, now);
15695
+ this.load = this.load.map((avg, i) => {
15696
+ const window = LOAD_WINDOWS_MS[i];
15697
+ const fresh2 = 1 - Math.exp(-LOAD_SAMPLE_MS / window);
15698
+ return avg * Math.exp(-elapsed / window) + running * fresh2;
15699
+ });
15700
+ }
15701
+ idleSince;
15702
+ sampling() {
15703
+ if (this.sampler) return;
15704
+ if (this.idleSince !== void 0) {
15705
+ const empty = Math.max(0, Date.now() - this.idleSince);
15706
+ this.load = this.load.map(
15707
+ (avg, i) => avg * Math.exp(-empty / LOAD_WINDOWS_MS[i])
15708
+ );
15709
+ }
15710
+ this.sampledAt = Date.now();
15711
+ this.sampler = setInterval(() => this.sampleLoad(), LOAD_SAMPLE_MS);
15712
+ this.sampler.unref?.();
15713
+ }
15714
+ spent = /* @__PURE__ */ new Map();
15715
+ timesAt(pid) {
15716
+ return this.processes.get(pid)?.times?.() ?? this.spent.get(pid);
15717
+ }
15718
+ timesOf(member, members) {
15719
+ let utime = 0;
15720
+ let stime = 0;
15721
+ let timed2 = false;
15722
+ for (let at = member; at; at = members.get(at.execParent ?? -1)) {
15723
+ const t = this.timesAt(at.pid);
15724
+ if (!t) continue;
15725
+ timed2 = true;
15726
+ utime += t.utime;
15727
+ stime += t.stime;
15728
+ }
15729
+ return timed2 ? { utime, stime } : {};
15730
+ }
15489
15731
  list(viewer = ROOT) {
15490
15732
  const members = new Map(this.jobs.list().map((member) => [member.pid, member]));
15491
15733
  const rootOf = (member) => {
@@ -15517,6 +15759,7 @@ var Launcher = class {
15517
15759
  started: (this.described.get(root.pid) ?? described2).started,
15518
15760
  state: this.processes.has(member.pid) ? "S" : "Z",
15519
15761
  memory: this.processes.get(member.pid)?.memory() ?? 0,
15762
+ ...this.timesOf(member, members),
15520
15763
  umask: this.umaskOf(member.pid),
15521
15764
  cred,
15522
15765
  ...this.signalMasksOf(member.pid)