@andersbakken/fisk 4.0.55 → 4.0.57
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/daemon/fisk-daemon.js +156 -1
- package/monitor/fisk-monitor.js +94 -1
- package/package.json +1 -1
package/daemon/fisk-daemon.js
CHANGED
|
@@ -42,6 +42,12 @@ const Constants = {
|
|
|
42
42
|
get JSON() {
|
|
43
43
|
return 5;
|
|
44
44
|
},
|
|
45
|
+
get AcquireSlot() {
|
|
46
|
+
return 6;
|
|
47
|
+
},
|
|
48
|
+
get ReleaseLocalSlot() {
|
|
49
|
+
return 7;
|
|
50
|
+
},
|
|
45
51
|
// daemon codes
|
|
46
52
|
get CppSlotAcquired() {
|
|
47
53
|
return 10;
|
|
@@ -51,6 +57,9 @@ const Constants = {
|
|
|
51
57
|
},
|
|
52
58
|
get JSONResponse() {
|
|
53
59
|
return 12;
|
|
60
|
+
},
|
|
61
|
+
get LocalSlotAcquired() {
|
|
62
|
+
return 13;
|
|
54
63
|
}
|
|
55
64
|
};
|
|
56
65
|
|
|
@@ -208,6 +217,12 @@ class Compile extends EventEmitter__default["default"] {
|
|
|
208
217
|
case Constants.ReleaseCompileSlot:
|
|
209
218
|
emit("releaseCompileSlot");
|
|
210
219
|
continue;
|
|
220
|
+
case Constants.AcquireSlot:
|
|
221
|
+
emit("acquireSlot");
|
|
222
|
+
continue;
|
|
223
|
+
case Constants.ReleaseLocalSlot:
|
|
224
|
+
emit("releaseLocalSlot");
|
|
225
|
+
continue;
|
|
211
226
|
case Constants.JSON:
|
|
212
227
|
if (available < 5) {
|
|
213
228
|
break;
|
|
@@ -3330,16 +3345,40 @@ class Slots extends EventEmitter__default["default"] {
|
|
|
3330
3345
|
this.debug = debug;
|
|
3331
3346
|
this.used = new Map();
|
|
3332
3347
|
this.pending = new Map();
|
|
3348
|
+
this._totalAcquired = 0;
|
|
3333
3349
|
if (this.debug) {
|
|
3334
3350
|
console.log("Slots created", this.toString());
|
|
3335
3351
|
}
|
|
3336
3352
|
}
|
|
3353
|
+
get capacity() {
|
|
3354
|
+
return this.count;
|
|
3355
|
+
}
|
|
3356
|
+
get active() {
|
|
3357
|
+
return this.used.size;
|
|
3358
|
+
}
|
|
3359
|
+
get totalAcquired() {
|
|
3360
|
+
return this._totalAcquired;
|
|
3361
|
+
}
|
|
3362
|
+
tryAcquire(id, data) {
|
|
3363
|
+
if (this.used.size < this.count) {
|
|
3364
|
+
this.used.set(id, data);
|
|
3365
|
+
++this._totalAcquired;
|
|
3366
|
+
if (this.debug) {
|
|
3367
|
+
console.log("tryAcquire succeeded", id, data, this.toString());
|
|
3368
|
+
}
|
|
3369
|
+
this.emit("changed");
|
|
3370
|
+
return true;
|
|
3371
|
+
}
|
|
3372
|
+
return false;
|
|
3373
|
+
}
|
|
3337
3374
|
acquire(id, data, cb) {
|
|
3338
3375
|
if (this.used.size < this.count) {
|
|
3339
3376
|
this.used.set(id, data);
|
|
3377
|
+
++this._totalAcquired;
|
|
3340
3378
|
if (this.debug) {
|
|
3341
3379
|
console.log("acquired slot", id, data, this.toString());
|
|
3342
3380
|
}
|
|
3381
|
+
this.emit("changed");
|
|
3343
3382
|
cb();
|
|
3344
3383
|
}
|
|
3345
3384
|
else {
|
|
@@ -3363,9 +3402,11 @@ class Slots extends EventEmitter__default["default"] {
|
|
|
3363
3402
|
for (const p of this.pending) {
|
|
3364
3403
|
this.used.set(p[0], p[1].data);
|
|
3365
3404
|
this.pending.delete(p[0]);
|
|
3405
|
+
++this._totalAcquired;
|
|
3366
3406
|
p[1].cb();
|
|
3367
3407
|
break;
|
|
3368
3408
|
}
|
|
3409
|
+
this.emit("changed");
|
|
3369
3410
|
}
|
|
3370
3411
|
}
|
|
3371
3412
|
toString() {
|
|
@@ -4118,6 +4159,8 @@ Options:
|
|
|
4118
4159
|
--socket=PATH Unix socket path (default: ~/.cache/fisk/daemon/socket)
|
|
4119
4160
|
--cpp-slots=N Preprocess slot count (default: cpus * 2)
|
|
4120
4161
|
--slots=N Compile slot count (default: cpus)
|
|
4162
|
+
--local-slots=N Local compile slot count (default: 0, disabled)
|
|
4163
|
+
--local-slots-max-load=N Max system load average (1-min) to allow local compiles (default: 0, no limit)
|
|
4121
4164
|
--cache-dir=PATH Cache directory (default: ~/.cache/fisk/daemon)
|
|
4122
4165
|
|
|
4123
4166
|
Config files: ~/.config/fisk/daemon.conf, /etc/xdg/fisk/daemon.conf
|
|
@@ -4153,15 +4196,87 @@ server.on("error", (err) => {
|
|
|
4153
4196
|
});
|
|
4154
4197
|
const cppSlots = new Slots(option.int("cpp-slots", Math.max(os__default["default"].cpus().length * 2, 1)), "cpp", debug);
|
|
4155
4198
|
const compileSlots = new Slots(option.int("slots", Math.max(os__default["default"].cpus().length, 1)), "compile", debug);
|
|
4199
|
+
const localSlotCount = option.int("local-slots", 0);
|
|
4200
|
+
const localSlots = new Slots(localSlotCount, "local", debug);
|
|
4201
|
+
const localSlotsMaxLoad = option("local-slots-max-load") || 0;
|
|
4202
|
+
const slotSubscribers = [];
|
|
4203
|
+
function slotsInfo() {
|
|
4204
|
+
return {
|
|
4205
|
+
type: "slotsInfo",
|
|
4206
|
+
local: {
|
|
4207
|
+
active: localSlots.active,
|
|
4208
|
+
capacity: localSlots.capacity,
|
|
4209
|
+
total: localSlots.totalAcquired
|
|
4210
|
+
},
|
|
4211
|
+
cpp: {
|
|
4212
|
+
active: cppSlots.active,
|
|
4213
|
+
capacity: cppSlots.capacity,
|
|
4214
|
+
total: cppSlots.totalAcquired
|
|
4215
|
+
},
|
|
4216
|
+
compile: {
|
|
4217
|
+
active: compileSlots.active,
|
|
4218
|
+
capacity: compileSlots.capacity,
|
|
4219
|
+
total: compileSlots.totalAcquired
|
|
4220
|
+
}
|
|
4221
|
+
};
|
|
4222
|
+
}
|
|
4223
|
+
function broadcastSlotsInfo() {
|
|
4224
|
+
if (slotSubscribers.length === 0) {
|
|
4225
|
+
return;
|
|
4226
|
+
}
|
|
4227
|
+
const info = slotsInfo();
|
|
4228
|
+
for (const sub of slotSubscribers) {
|
|
4229
|
+
sub.compile.send(info);
|
|
4230
|
+
}
|
|
4231
|
+
}
|
|
4232
|
+
for (const slots of [localSlots, cppSlots, compileSlots]) {
|
|
4233
|
+
slots.on("changed", broadcastSlotsInfo);
|
|
4234
|
+
}
|
|
4235
|
+
function canAcquireLocalSlot() {
|
|
4236
|
+
if (localSlotCount <= 0) {
|
|
4237
|
+
return false;
|
|
4238
|
+
}
|
|
4239
|
+
if (localSlotsMaxLoad > 0) {
|
|
4240
|
+
const loadAvg = os__default["default"].loadavg()[0];
|
|
4241
|
+
if (loadAvg > localSlotsMaxLoad) {
|
|
4242
|
+
if (debug) {
|
|
4243
|
+
console.log(`Local slot denied: load ${loadAvg.toFixed(2)} > max ${localSlotsMaxLoad}`);
|
|
4244
|
+
}
|
|
4245
|
+
return false;
|
|
4246
|
+
}
|
|
4247
|
+
}
|
|
4248
|
+
return true;
|
|
4249
|
+
}
|
|
4156
4250
|
server.on("compile", (compile) => {
|
|
4157
4251
|
compile.on("dumpSlots", () => {
|
|
4158
|
-
const ret = { cpp: cppSlots.dump(), compile: compileSlots.dump() };
|
|
4252
|
+
const ret = { cpp: cppSlots.dump(), compile: compileSlots.dump(), local: localSlots.dump() };
|
|
4159
4253
|
if (debug) {
|
|
4160
4254
|
console.log("sending dump", ret);
|
|
4161
4255
|
}
|
|
4162
4256
|
compile.send(ret);
|
|
4163
4257
|
});
|
|
4258
|
+
compile.on("subscribeSlots", () => {
|
|
4259
|
+
if (debug) {
|
|
4260
|
+
console.log("subscribeSlots from", compile.id);
|
|
4261
|
+
}
|
|
4262
|
+
const subscriber = {
|
|
4263
|
+
compile,
|
|
4264
|
+
handler: () => {
|
|
4265
|
+
// Remove subscriber on disconnect
|
|
4266
|
+
const idx = slotSubscribers.indexOf(subscriber);
|
|
4267
|
+
if (idx !== -1) {
|
|
4268
|
+
slotSubscribers.splice(idx, 1);
|
|
4269
|
+
}
|
|
4270
|
+
}
|
|
4271
|
+
};
|
|
4272
|
+
slotSubscribers.push(subscriber);
|
|
4273
|
+
compile.on("end", subscriber.handler);
|
|
4274
|
+
compile.on("error", subscriber.handler);
|
|
4275
|
+
// Send current state immediately
|
|
4276
|
+
compile.send(slotsInfo());
|
|
4277
|
+
});
|
|
4164
4278
|
let requestedCppSlot = false;
|
|
4279
|
+
let requestedLocalSlot = false;
|
|
4165
4280
|
compile.on("acquireCppSlot", () => {
|
|
4166
4281
|
if (debug) {
|
|
4167
4282
|
console.log("acquireCppSlot");
|
|
@@ -4205,6 +4320,38 @@ server.on("compile", (compile) => {
|
|
|
4205
4320
|
compileSlots.release(compile.id);
|
|
4206
4321
|
}
|
|
4207
4322
|
});
|
|
4323
|
+
compile.on("acquireSlot", () => {
|
|
4324
|
+
if (debug) {
|
|
4325
|
+
console.log("acquireSlot");
|
|
4326
|
+
}
|
|
4327
|
+
if (canAcquireLocalSlot() && localSlots.tryAcquire(compile.id, { pid: compile.pid })) {
|
|
4328
|
+
if (debug) {
|
|
4329
|
+
console.log("acquireSlot -> local slot granted");
|
|
4330
|
+
}
|
|
4331
|
+
requestedLocalSlot = true;
|
|
4332
|
+
compile.send(Constants.LocalSlotAcquired);
|
|
4333
|
+
}
|
|
4334
|
+
else {
|
|
4335
|
+
if (debug) {
|
|
4336
|
+
console.log("acquireSlot -> falling back to cpp slot");
|
|
4337
|
+
}
|
|
4338
|
+
assert__default["default"](!requestedCppSlot);
|
|
4339
|
+
requestedCppSlot = true;
|
|
4340
|
+
cppSlots.acquire(compile.id, { pid: compile.pid }, () => {
|
|
4341
|
+
compile.send(Constants.CppSlotAcquired);
|
|
4342
|
+
});
|
|
4343
|
+
}
|
|
4344
|
+
});
|
|
4345
|
+
compile.on("releaseLocalSlot", () => {
|
|
4346
|
+
if (debug) {
|
|
4347
|
+
console.log("releaseLocalSlot");
|
|
4348
|
+
}
|
|
4349
|
+
assert__default["default"](requestedLocalSlot);
|
|
4350
|
+
if (requestedLocalSlot) {
|
|
4351
|
+
requestedLocalSlot = false;
|
|
4352
|
+
localSlots.release(compile.id);
|
|
4353
|
+
}
|
|
4354
|
+
});
|
|
4208
4355
|
compile.on("error", (err) => {
|
|
4209
4356
|
if (debug) {
|
|
4210
4357
|
console.error("Got error from fiskc", compile.id, compile.pid, err);
|
|
@@ -4217,6 +4364,10 @@ server.on("compile", (compile) => {
|
|
|
4217
4364
|
requestedCompileSlot = false;
|
|
4218
4365
|
compileSlots.release(compile.id);
|
|
4219
4366
|
}
|
|
4367
|
+
if (requestedLocalSlot) {
|
|
4368
|
+
requestedLocalSlot = false;
|
|
4369
|
+
localSlots.release(compile.id);
|
|
4370
|
+
}
|
|
4220
4371
|
});
|
|
4221
4372
|
compile.on("end", () => {
|
|
4222
4373
|
if (debug) {
|
|
@@ -4230,6 +4381,10 @@ server.on("compile", (compile) => {
|
|
|
4230
4381
|
requestedCompileSlot = false;
|
|
4231
4382
|
compileSlots.release(compile.id);
|
|
4232
4383
|
}
|
|
4384
|
+
if (requestedLocalSlot) {
|
|
4385
|
+
requestedLocalSlot = false;
|
|
4386
|
+
localSlots.release(compile.id);
|
|
4387
|
+
}
|
|
4233
4388
|
});
|
|
4234
4389
|
});
|
|
4235
4390
|
process.on("exit", () => {
|
package/monitor/fisk-monitor.js
CHANGED
|
@@ -5895,6 +5895,7 @@ if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
|
5895
5895
|
|
|
5896
5896
|
Options:
|
|
5897
5897
|
--scheduler=URL Scheduler URL (default: ws://localhost:8097)
|
|
5898
|
+
--daemon-socket=PATH Daemon Unix socket path (default: ~/.cache/fisk/daemon/socket)
|
|
5898
5899
|
|
|
5899
5900
|
Config files: ~/.config/fisk/monitor.conf, /etc/xdg/fisk/monitor.conf
|
|
5900
5901
|
Environment variables: FISK_MONITOR_SCHEDULER, etc.`);
|
|
@@ -6298,7 +6299,13 @@ function notify(msg) {
|
|
|
6298
6299
|
return;
|
|
6299
6300
|
}
|
|
6300
6301
|
const notifyNow = (message) => {
|
|
6301
|
-
|
|
6302
|
+
if (message) {
|
|
6303
|
+
notificationBox.setContent(message);
|
|
6304
|
+
}
|
|
6305
|
+
else {
|
|
6306
|
+
updateNotificationBar();
|
|
6307
|
+
return;
|
|
6308
|
+
}
|
|
6302
6309
|
screen.render();
|
|
6303
6310
|
};
|
|
6304
6311
|
notificationInterval = setInterval(() => {
|
|
@@ -6624,5 +6631,91 @@ function connect() {
|
|
|
6624
6631
|
setTimeout(connect, 1000);
|
|
6625
6632
|
});
|
|
6626
6633
|
}
|
|
6634
|
+
// --- Daemon connection for local slot info ---
|
|
6635
|
+
const DaemonJSON = 5;
|
|
6636
|
+
const DaemonJSONResponse = 12;
|
|
6637
|
+
const daemonSocketPath = String(option("daemon-socket", path__default["default"].join(require$$2__default["default"].homedir(), ".cache", "fisk", "daemon", "socket")));
|
|
6638
|
+
let daemonSlotsInfo;
|
|
6639
|
+
let daemonSocket;
|
|
6640
|
+
let daemonRecvBuffer = Buffer.alloc(0);
|
|
6641
|
+
function updateNotificationBar() {
|
|
6642
|
+
if (daemonSlotsInfo && daemonSlotsInfo.local.capacity > 0) {
|
|
6643
|
+
const local = daemonSlotsInfo.local;
|
|
6644
|
+
notificationBox.setContent(`{bold}Local:{/bold} ${local.active}/${local.capacity} active, ${local.total} total`);
|
|
6645
|
+
}
|
|
6646
|
+
else {
|
|
6647
|
+
notificationBox.setContent("");
|
|
6648
|
+
}
|
|
6649
|
+
screen.render();
|
|
6650
|
+
}
|
|
6651
|
+
function processDaemonMessage(json) {
|
|
6652
|
+
try {
|
|
6653
|
+
const msg = JSON.parse(json);
|
|
6654
|
+
if (msg.type === "slotsInfo") {
|
|
6655
|
+
daemonSlotsInfo = msg;
|
|
6656
|
+
updateNotificationBar();
|
|
6657
|
+
}
|
|
6658
|
+
}
|
|
6659
|
+
catch (e) {
|
|
6660
|
+
// ignore parse errors
|
|
6661
|
+
}
|
|
6662
|
+
}
|
|
6663
|
+
function processDaemonData() {
|
|
6664
|
+
while (daemonRecvBuffer.length > 0) {
|
|
6665
|
+
const type = daemonRecvBuffer[0];
|
|
6666
|
+
if (type === DaemonJSONResponse) {
|
|
6667
|
+
if (daemonRecvBuffer.length < 5) {
|
|
6668
|
+
break; // need more data for length header
|
|
6669
|
+
}
|
|
6670
|
+
const msgLen = daemonRecvBuffer.readUInt32BE(1);
|
|
6671
|
+
if (daemonRecvBuffer.length < 5 + msgLen) {
|
|
6672
|
+
break; // need more data for body
|
|
6673
|
+
}
|
|
6674
|
+
const json = daemonRecvBuffer.subarray(5, 5 + msgLen).toString("utf8");
|
|
6675
|
+
daemonRecvBuffer = daemonRecvBuffer.subarray(5 + msgLen);
|
|
6676
|
+
processDaemonMessage(json);
|
|
6677
|
+
}
|
|
6678
|
+
else {
|
|
6679
|
+
// Unknown single-byte message, skip it
|
|
6680
|
+
daemonRecvBuffer = daemonRecvBuffer.subarray(1);
|
|
6681
|
+
}
|
|
6682
|
+
}
|
|
6683
|
+
}
|
|
6684
|
+
function sendDaemonJSON(sock, obj) {
|
|
6685
|
+
const jsonBuf = Buffer.from(JSON.stringify(obj), "utf8");
|
|
6686
|
+
const header = Buffer.allocUnsafe(5);
|
|
6687
|
+
header.writeUInt8(DaemonJSON, 0);
|
|
6688
|
+
header.writeUInt32BE(jsonBuf.length, 1);
|
|
6689
|
+
sock.write(header);
|
|
6690
|
+
sock.write(jsonBuf);
|
|
6691
|
+
}
|
|
6692
|
+
function connectDaemon() {
|
|
6693
|
+
daemonSlotsInfo = undefined;
|
|
6694
|
+
daemonRecvBuffer = Buffer.alloc(0);
|
|
6695
|
+
daemonSocket = require$$3__default["default"].createConnection(daemonSocketPath);
|
|
6696
|
+
daemonSocket.on("connect", () => {
|
|
6697
|
+
assert__default["default"](daemonSocket);
|
|
6698
|
+
// Send PID (4 bytes, big-endian) as the daemon protocol requires
|
|
6699
|
+
const pidBuf = Buffer.allocUnsafe(4);
|
|
6700
|
+
pidBuf.writeUInt32BE(process.pid, 0);
|
|
6701
|
+
daemonSocket.write(pidBuf);
|
|
6702
|
+
// Subscribe to slot updates
|
|
6703
|
+
sendDaemonJSON(daemonSocket, { type: "subscribeSlots" });
|
|
6704
|
+
});
|
|
6705
|
+
daemonSocket.on("data", (data) => {
|
|
6706
|
+
daemonRecvBuffer = Buffer.concat([daemonRecvBuffer, data]);
|
|
6707
|
+
processDaemonData();
|
|
6708
|
+
});
|
|
6709
|
+
daemonSocket.on("error", () => {
|
|
6710
|
+
// Daemon may not be running, silently retry
|
|
6711
|
+
});
|
|
6712
|
+
daemonSocket.on("close", () => {
|
|
6713
|
+
daemonSocket = undefined;
|
|
6714
|
+
daemonSlotsInfo = undefined;
|
|
6715
|
+
updateNotificationBar();
|
|
6716
|
+
setTimeout(connectDaemon, 5000);
|
|
6717
|
+
});
|
|
6718
|
+
}
|
|
6627
6719
|
connect();
|
|
6720
|
+
connectDaemon();
|
|
6628
6721
|
//# sourceMappingURL=fisk-monitor.js.map
|