@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.
package/dist/node.js CHANGED
@@ -5535,11 +5535,11 @@ var ChildTable = class {
5535
5535
  return [...this.children.keys()];
5536
5536
  }
5537
5537
  captured(pid, slot2) {
5538
- const slots = this.leftovers.get(pid);
5539
- const chunks2 = slots?.get(slot2);
5540
- if (!slots || !chunks2) return new Uint8Array(0);
5541
- slots.delete(slot2);
5542
- if (slots.size === 0) this.leftovers.delete(pid);
5538
+ const slots2 = this.leftovers.get(pid);
5539
+ const chunks2 = slots2?.get(slot2);
5540
+ if (!slots2 || !chunks2) return new Uint8Array(0);
5541
+ slots2.delete(slot2);
5542
+ if (slots2.size === 0) this.leftovers.delete(pid);
5543
5543
  return concat2(chunks2);
5544
5544
  }
5545
5545
  };
@@ -7011,7 +7011,9 @@ async function dispatchOne(entry, req) {
7011
7011
 
7012
7012
  // src/realm/sync-sab-wire.ts
7013
7013
  var SAB_HEADER_I32 = 16;
7014
- var SAB_HEADER_BYTES = SAB_HEADER_I32 * 4;
7014
+ var SAB_CLOCK_OFFSET = SAB_HEADER_I32 * 4;
7015
+ var SAB_CLOCK_I64 = 3;
7016
+ var SAB_HEADER_BYTES = SAB_CLOCK_OFFSET + SAB_CLOCK_I64 * 8;
7015
7017
  var SAB_I_STATE = 0;
7016
7018
  var SAB_I_SEQ = 1;
7017
7019
  var SAB_I_STATUS = 2;
@@ -7161,6 +7163,146 @@ function attachSyncSabResponder(port, sab, token, opts) {
7161
7163
  };
7162
7164
  }
7163
7165
 
7166
+ // src/kernel/cpu-clock.ts
7167
+ var IDLE_OPS = /* @__PURE__ */ new Set([
7168
+ "fd-select",
7169
+ "proc-wait",
7170
+ "proc-exec",
7171
+ "sig-pause",
7172
+ "sock-accept",
7173
+ "sock-connect"
7174
+ ]);
7175
+ var SYS_CAP_US = 2e4;
7176
+ var LOCAL = SAB_CLOCK_OFFSET;
7177
+ var IDLE = 1;
7178
+ function epochMicros() {
7179
+ return Math.floor((performance.timeOrigin + performance.now()) * 1e3);
7180
+ }
7181
+ function slots(sab) {
7182
+ return new BigInt64Array(sab, LOCAL, SAB_CLOCK_I64);
7183
+ }
7184
+ var rawWait = Atomics.wait.bind(Atomics);
7185
+ function localIdle(sab, now) {
7186
+ const state = Number(Atomics.load(slots(sab), IDLE));
7187
+ if (state >= 0) return { idle: state, waiting: false };
7188
+ return { idle: Math.max(0, now + state), waiting: true };
7189
+ }
7190
+ var CpuClock = class {
7191
+ start;
7192
+ sys = 0;
7193
+ idle = 0;
7194
+ since = 0;
7195
+ kind = "sys";
7196
+ stopped = false;
7197
+ last = { utime: 0, stime: 0 };
7198
+ sab;
7199
+ now;
7200
+ constructor(sab, now = epochMicros) {
7201
+ this.sab = sab;
7202
+ this.now = now;
7203
+ this.start = now();
7204
+ }
7205
+ enter(op) {
7206
+ this.since = this.now();
7207
+ this.kind = this.stopped || IDLE_OPS.has(op) ? "idle" : "sys";
7208
+ }
7209
+ leave() {
7210
+ if (this.since === 0) return;
7211
+ this.add((this.frozen ?? this.now()) - this.since);
7212
+ this.since = 0;
7213
+ }
7214
+ stop(stopped) {
7215
+ if (stopped === this.stopped) return;
7216
+ this.stopped = stopped;
7217
+ if (this.since === 0 || !stopped || this.frozen !== void 0) return;
7218
+ const now = this.now();
7219
+ this.add(now - this.since);
7220
+ this.since = now;
7221
+ this.kind = "idle";
7222
+ }
7223
+ frozen;
7224
+ freeze() {
7225
+ this.frozen ??= this.now();
7226
+ }
7227
+ running() {
7228
+ if (this.frozen !== void 0) return false;
7229
+ const now = this.now();
7230
+ const busy = this.since === 0 || this.kind === "sys" && now - this.since < SYS_CAP_US;
7231
+ return busy && !localIdle(this.sab, now).waiting;
7232
+ }
7233
+ times() {
7234
+ const now = this.frozen ?? this.now();
7235
+ const open = this.since === 0 ? 0 : Math.max(0, now - this.since);
7236
+ const busy = this.kind === "sys" ? Math.min(open, SYS_CAP_US) : 0;
7237
+ const sys = this.sys + busy;
7238
+ const idle = this.idle + (open - busy) + localIdle(this.sab, now).idle;
7239
+ const user = Math.max(0, now - this.start - sys - idle);
7240
+ this.last = {
7241
+ utime: Math.max(this.last.utime, Math.floor(user / 1e3)),
7242
+ stime: Math.max(this.last.stime, Math.floor(sys / 1e3))
7243
+ };
7244
+ return this.last;
7245
+ }
7246
+ add(micros) {
7247
+ const spent = Math.max(0, micros);
7248
+ const busy = this.kind === "sys" ? Math.min(spent, SYS_CAP_US) : 0;
7249
+ this.sys += busy;
7250
+ this.idle += spent - busy;
7251
+ }
7252
+ };
7253
+ var ProcessClocks = class {
7254
+ main;
7255
+ threads = /* @__PURE__ */ new Map();
7256
+ ended = { utime: 0, stime: 0 };
7257
+ enabled;
7258
+ constructor(sab, enabled = true, states) {
7259
+ this.main = new CpuClock(sab);
7260
+ this.enabled = enabled;
7261
+ states?.onState((state) => this.stop(state === "stopped"));
7262
+ }
7263
+ thread(tid, sab) {
7264
+ const clock = new CpuClock(sab);
7265
+ this.threads.set(tid, clock);
7266
+ return clock;
7267
+ }
7268
+ threadEnded(tid) {
7269
+ const spent = this.threads.get(tid)?.times();
7270
+ this.threads.delete(tid);
7271
+ if (!spent) return;
7272
+ this.ended.utime += spent.utime;
7273
+ this.ended.stime += spent.stime;
7274
+ }
7275
+ stop(stopped) {
7276
+ for (const c of this.all()) c.stop(stopped);
7277
+ }
7278
+ freeze() {
7279
+ for (const c of this.all()) c.freeze();
7280
+ }
7281
+ times() {
7282
+ if (!this.enabled) return void 0;
7283
+ const sum = { ...this.ended };
7284
+ for (const c of this.all()) {
7285
+ const t = c.times();
7286
+ sum.utime += t.utime;
7287
+ sum.stime += t.stime;
7288
+ }
7289
+ return sum;
7290
+ }
7291
+ running() {
7292
+ return this.enabled ? this.all().filter((c) => c.running()).length : 0;
7293
+ }
7294
+ timed(clock, dispatch2) {
7295
+ const c = clock ?? this.main;
7296
+ return (req) => {
7297
+ c.enter(req.op);
7298
+ return dispatch2(req).finally(() => c.leave());
7299
+ };
7300
+ }
7301
+ all() {
7302
+ return [this.main, ...this.threads.values()];
7303
+ }
7304
+ };
7305
+
7164
7306
  // src/kernel/net/loopback-names.ts
7165
7307
  var HOST_LOOPBACK = "host.slicc.internal";
7166
7308
  var HOST_LOOPBACK_ADDRESS = [10, 0, 2, 2];
@@ -7472,8 +7614,8 @@ function pidStat(info, boot) {
7472
7614
  0,
7473
7615
  0,
7474
7616
  0,
7475
- 0,
7476
- 0,
7617
+ ticks(info.utime ?? 0),
7618
+ ticks(info.stime ?? 0),
7477
7619
  0,
7478
7620
  0,
7479
7621
  20,
@@ -7567,19 +7709,23 @@ function systemFile(name2, listing, now, memory) {
7567
7709
  if (name2 === "meminfo") {
7568
7710
  return memoryInfo(
7569
7711
  memory,
7570
- listing.processes.reduce((sum, p) => sum + p.memory, 0)
7712
+ listing.processes.reduce((sum2, p) => sum2 + p.memory, 0)
7571
7713
  );
7572
7714
  }
7573
7715
  const live = listing.processes.filter((p) => p.state !== "Z");
7574
7716
  if (name2 === "loadavg") {
7575
7717
  const last = Math.max(0, ...listing.processes.map((p) => p.pid));
7576
- return `0.00 0.00 0.00 1/${live.length} ${last}
7718
+ const [one, five, fifteen] = (listing.load ?? [0, 0, 0]).map((n) => n.toFixed(2));
7719
+ return `${one} ${five} ${fifteen} 1/${live.length} ${last}
7577
7720
  `;
7578
7721
  }
7579
- const idle = ticks(now - listing.boot);
7722
+ const sum = (key) => listing.cpu?.[key] ?? listing.processes.reduce((n, p) => n + (p[key] ?? 0), 0);
7723
+ const user = ticks(sum("utime"));
7724
+ const system = ticks(sum("stime"));
7725
+ const idle = listing.cpu ? ticks(listing.cpu.idle) : Math.max(0, ticks(now - listing.boot) - user - system);
7580
7726
  return [
7581
- `cpu 0 0 0 ${idle} 0 0 0 0 0 0`,
7582
- `cpu0 0 0 0 ${idle} 0 0 0 0 0 0`,
7727
+ `cpu ${user} 0 ${system} ${idle} 0 0 0 0 0 0`,
7728
+ `cpu0 ${user} 0 ${system} ${idle} 0 0 0 0 0 0`,
7583
7729
  "intr 0",
7584
7730
  "ctxt 0",
7585
7731
  `btime ${Math.floor(listing.boot / 1e3)}`,
@@ -12039,6 +12185,9 @@ function killThread(thread, caught, sig) {
12039
12185
  blocked.abort();
12040
12186
  return true;
12041
12187
  }
12188
+ function threadSignalsOf(sab) {
12189
+ return { header: new Int32Array(sab, 0, SAB_HEADER_I32), interrupt: new AbortController() };
12190
+ }
12042
12191
  function threadCancel(thread) {
12043
12192
  return Atomics.load(thread.header, SAB_I_SIGNALS) !== 0 ? AbortSignal.abort() : thread.interrupt.signal;
12044
12193
  }
@@ -12164,6 +12313,22 @@ function processOptions(opts, header4, hooks, created3) {
12164
12313
  ...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header4, SAB_I_SIGNALS) } : {}
12165
12314
  };
12166
12315
  }
12316
+ function threadInit(opts, program, sab, cred, thread) {
12317
+ return {
12318
+ type: WASM_THREAD_INIT,
12319
+ pid: opts.shownPid ?? opts.pid,
12320
+ program,
12321
+ argv0: opts.argv0,
12322
+ args: opts.args,
12323
+ env: opts.env,
12324
+ cwd: opts.cwd,
12325
+ sab,
12326
+ cred: copyCred(cred),
12327
+ owners: opts.owners === true,
12328
+ ...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
12329
+ thread
12330
+ };
12331
+ }
12167
12332
  function spawnWasmProcess(opts) {
12168
12333
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
12169
12334
  const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
@@ -12196,7 +12361,10 @@ function spawnWasmProcess(opts) {
12196
12361
  const worker = opts.createWorker();
12197
12362
  const dying = new Dying();
12198
12363
  const dispatch2 = (req) => dying.serving(() => isWasmSyscall(req) ? process2.syscall(req) : dispatchSyncFs(req));
12199
- const responder = attachSyncSabResponder(worker, sab, token, { dispatch: dispatch2 });
12364
+ const clocks = new ProcessClocks(sab, opts.program.abi !== "js", process2);
12365
+ const responder = attachSyncSabResponder(worker, sab, token, {
12366
+ dispatch: clocks.timed(void 0, dispatch2)
12367
+ });
12200
12368
  const lane = opts.program.abi === "js" ? openLane(token, dispatch2) : void 0;
12201
12369
  const { promise: exited, resolve: settle } = Promise.withResolvers();
12202
12370
  let done4 = false;
@@ -12204,6 +12372,7 @@ function spawnWasmProcess(opts) {
12204
12372
  const finish = (code, sig) => {
12205
12373
  if (done4) return;
12206
12374
  done4 = true;
12375
+ clocks.freeze();
12207
12376
  dying.clear();
12208
12377
  endedBy = sig ?? process2.execTermsig;
12209
12378
  worker.removeEventListener("message", onMessage);
@@ -12244,6 +12413,7 @@ function spawnWasmProcess(opts) {
12244
12413
  const endThread = (tid) => {
12245
12414
  const end = threads.get(tid);
12246
12415
  threads.delete(tid);
12416
+ clocks.threadEnded(tid);
12247
12417
  process2.threadEnded(tid);
12248
12418
  end?.();
12249
12419
  };
@@ -12257,15 +12427,14 @@ function spawnWasmProcess(opts) {
12257
12427
  }
12258
12428
  const tsab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
12259
12429
  const tw = opts.createWorker();
12260
- const tsignals = {
12261
- header: new Int32Array(tsab, 0, SAB_HEADER_I32),
12262
- interrupt: new AbortController()
12263
- };
12430
+ const tsignals = threadSignalsOf(tsab);
12264
12431
  threadSignals.set(thread.tid, tsignals);
12265
12432
  const tdispatch = (req) => dying.serving(
12266
12433
  () => isWasmSyscall(req) ? process2.syscall(req, threadCancel(tsignals)) : dispatchSyncFs(req)
12267
12434
  );
12268
- const tresponder = attachSyncSabResponder(tw, tsab, token, { dispatch: tdispatch });
12435
+ const tresponder = attachSyncSabResponder(tw, tsab, token, {
12436
+ dispatch: clocks.timed(clocks.thread(thread.tid, tsab), tdispatch)
12437
+ });
12269
12438
  const onThreadMessage = (event) => {
12270
12439
  const data = event.data;
12271
12440
  if (data?.type === WASM_THREAD_EXIT) endThread(thread.tid);
@@ -12280,21 +12449,7 @@ function spawnWasmProcess(opts) {
12280
12449
  tresponder.dispose();
12281
12450
  tw.terminate();
12282
12451
  });
12283
- const tinit = {
12284
- type: WASM_THREAD_INIT,
12285
- pid: opts.shownPid ?? opts.pid,
12286
- program,
12287
- argv0: opts.argv0,
12288
- args: opts.args,
12289
- env: opts.env,
12290
- cwd: opts.cwd,
12291
- sab: tsab,
12292
- cred: copyCred(process2.cred),
12293
- owners: opts.owners === true,
12294
- ...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
12295
- thread
12296
- };
12297
- tw.postMessage(tinit);
12452
+ tw.postMessage(threadInit(opts, program, tsab, process2.cred, thread));
12298
12453
  };
12299
12454
  worker.postMessage(
12300
12455
  processInit(opts, sab, process2.umask, copyCred(process2.cred), lane?.lane),
@@ -12319,7 +12474,9 @@ function spawnWasmProcess(opts) {
12319
12474
  signalMasks: () => process2.signalMasks(),
12320
12475
  umask: () => process2.umask,
12321
12476
  cred: () => copyCred(process2.cred),
12322
- writesBack: () => opts.program.abi === "wasi" && !done4
12477
+ writesBack: () => opts.program.abi === "wasi" && !done4,
12478
+ times: () => clocks.times(),
12479
+ running: () => clocks.running()
12323
12480
  };
12324
12481
  }
12325
12482
 
@@ -14738,6 +14895,8 @@ var LAYOUT = [
14738
14895
  ["/usr", 493],
14739
14896
  ["/usr/local", 493]
14740
14897
  ];
14898
+ var LOAD_SAMPLE_MS = 5e3;
14899
+ var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
14741
14900
  var encoder3 = new TextEncoder();
14742
14901
  var USERS_MODES = ["off", "report", "enforce"];
14743
14902
  function usersMode(mode = "off") {
@@ -15266,6 +15425,7 @@ var Launcher = class {
15266
15425
  return this.jobs.sessionOf(pgid);
15267
15426
  }
15268
15427
  start(req) {
15428
+ this.sampling();
15269
15429
  if (req.pgid !== void 0 && this.jobs.sessionOf(req.pgid) === void 0) {
15270
15430
  throw fsError("ESRCH", `no process group ${req.pgid}`);
15271
15431
  }
@@ -15306,7 +15466,12 @@ var Launcher = class {
15306
15466
  forker: this.forker(pid, req),
15307
15467
  kill: (target, sig) => this.kill(target, sig, this.credOf(pid), pid),
15308
15468
  writesBack: (target) => this.processes.get(target)?.writesBack() === true,
15309
- processes: () => ({ boot: this.boot, processes: this.list(this.credOf(pid)) }),
15469
+ processes: () => ({
15470
+ boot: this.boot,
15471
+ processes: this.list(this.credOf(pid)),
15472
+ load: this.loadAverage(),
15473
+ cpu: this.cpuTotal()
15474
+ }),
15310
15475
  sudo: (call, signal) => this.sudo(pid, call, signal),
15311
15476
  openFiles: this.openFiles,
15312
15477
  nodes: this.nodes,
@@ -15340,7 +15505,14 @@ var Launcher = class {
15340
15505
  started: Date.now()
15341
15506
  });
15342
15507
  void handle.exited.then(() => {
15508
+ const spent = handle.times?.();
15509
+ if (spent) this.spent.set(pid, spent);
15343
15510
  this.processes.delete(pid);
15511
+ if (this.processes.size === 0) {
15512
+ clearInterval(this.sampler);
15513
+ this.sampler = void 0;
15514
+ this.idleSince = Date.now();
15515
+ }
15344
15516
  this.settling.settled(pid);
15345
15517
  if (req.ppid === void 0 || this.orphans.delete(pid)) this.forget(pid);
15346
15518
  else this.zombies.add(pid);
@@ -15356,6 +15528,12 @@ var Launcher = class {
15356
15528
  forget(pid) {
15357
15529
  this.jobs.remove(pid);
15358
15530
  this.described.delete(pid);
15531
+ const spent = this.spent.get(pid);
15532
+ if (spent) {
15533
+ this.reapedTimes.utime += spent.utime;
15534
+ this.reapedTimes.stime += spent.stime;
15535
+ }
15536
+ this.spent.delete(pid);
15359
15537
  this.creds.delete(pid);
15360
15538
  this.tags.delete(pid);
15361
15539
  this.granted.delete(pid);
@@ -15364,6 +15542,70 @@ var Launcher = class {
15364
15542
  if (this.zombies.delete(pid)) this.forget(pid);
15365
15543
  else this.orphans.add(pid);
15366
15544
  }
15545
+ load = [0, 0, 0];
15546
+ sampler;
15547
+ reapedTimes = { utime: 0, stime: 0 };
15548
+ idleAt = { wall: this.boot, busy: 0, idle: 0 };
15549
+ cpuTotal(now = Date.now()) {
15550
+ const total = { ...this.reapedTimes };
15551
+ const add = (t) => {
15552
+ total.utime += t?.utime ?? 0;
15553
+ total.stime += t?.stime ?? 0;
15554
+ };
15555
+ for (const handle of this.processes.values()) add(handle.times?.());
15556
+ for (const t of this.spent.values()) add(t);
15557
+ const busy = total.utime + total.stime;
15558
+ const at = this.idleAt;
15559
+ at.idle += Math.max(0, now - at.wall - (busy - at.busy));
15560
+ at.wall = Math.max(at.wall, now);
15561
+ at.busy = Math.max(at.busy, busy);
15562
+ return { ...total, idle: at.idle };
15563
+ }
15564
+ loadAverage() {
15565
+ return this.load;
15566
+ }
15567
+ sampledAt = Date.now();
15568
+ sampleLoad(now = Date.now()) {
15569
+ let running = 0;
15570
+ for (const handle of this.processes.values()) running += handle.running?.() ?? 0;
15571
+ const elapsed = Math.max(LOAD_SAMPLE_MS, now - this.sampledAt);
15572
+ this.sampledAt = Math.max(this.sampledAt, now);
15573
+ this.load = this.load.map((avg, i) => {
15574
+ const window = LOAD_WINDOWS_MS[i];
15575
+ const fresh2 = 1 - Math.exp(-LOAD_SAMPLE_MS / window);
15576
+ return avg * Math.exp(-elapsed / window) + running * fresh2;
15577
+ });
15578
+ }
15579
+ idleSince;
15580
+ sampling() {
15581
+ if (this.sampler) return;
15582
+ if (this.idleSince !== void 0) {
15583
+ const empty = Math.max(0, Date.now() - this.idleSince);
15584
+ this.load = this.load.map(
15585
+ (avg, i) => avg * Math.exp(-empty / LOAD_WINDOWS_MS[i])
15586
+ );
15587
+ }
15588
+ this.sampledAt = Date.now();
15589
+ this.sampler = setInterval(() => this.sampleLoad(), LOAD_SAMPLE_MS);
15590
+ this.sampler.unref?.();
15591
+ }
15592
+ spent = /* @__PURE__ */ new Map();
15593
+ timesAt(pid) {
15594
+ return this.processes.get(pid)?.times?.() ?? this.spent.get(pid);
15595
+ }
15596
+ timesOf(member, members) {
15597
+ let utime = 0;
15598
+ let stime = 0;
15599
+ let timed2 = false;
15600
+ for (let at = member; at; at = members.get(at.execParent ?? -1)) {
15601
+ const t = this.timesAt(at.pid);
15602
+ if (!t) continue;
15603
+ timed2 = true;
15604
+ utime += t.utime;
15605
+ stime += t.stime;
15606
+ }
15607
+ return timed2 ? { utime, stime } : {};
15608
+ }
15367
15609
  list(viewer = ROOT) {
15368
15610
  const members = new Map(this.jobs.list().map((member) => [member.pid, member]));
15369
15611
  const rootOf = (member) => {
@@ -15395,6 +15637,7 @@ var Launcher = class {
15395
15637
  started: (this.described.get(root.pid) ?? described2).started,
15396
15638
  state: this.processes.has(member.pid) ? "S" : "Z",
15397
15639
  memory: this.processes.get(member.pid)?.memory() ?? 0,
15640
+ ...this.timesOf(member, members),
15398
15641
  umask: this.umaskOf(member.pid),
15399
15642
  cred,
15400
15643
  ...this.signalMasksOf(member.pid)