aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorUri Shaked2020-12-12 15:01:17 +0200
committerUri Shaked2020-12-12 15:01:17 +0200
commite7ea8c76bd649aa84fdeb084fec02529743ee6eb (patch)
treeffe520a2f308a61805b04ddfbc3432a71205159c /src
parenttest(cpu): fix implicit any error (diff)
downloadavr8js-e7ea8c76bd649aa84fdeb084fec02529743ee6eb.tar.gz
avr8js-e7ea8c76bd649aa84fdeb084fec02529743ee6eb.tar.bz2
avr8js-e7ea8c76bd649aa84fdeb084fec02529743ee6eb.zip
perf(cpu): speed up event system
ditch `array.sort()` and instead manually keep the array sorted when we insert a new item.
Diffstat (limited to 'src')
-rw-r--r--src/cpu/cpu.spec.ts31
-rw-r--r--src/cpu/cpu.ts46
2 files changed, 59 insertions, 18 deletions
diff --git a/src/cpu/cpu.spec.ts b/src/cpu/cpu.spec.ts
index b1bc876..969b51c 100644
--- a/src/cpu/cpu.spec.ts
+++ b/src/cpu/cpu.spec.ts
@@ -26,6 +26,23 @@ describe('cpu', () => {
]);
});
+ it('should correctly sort the events when added in reverse order', () => {
+ const cpu = new CPU(new Uint16Array(1024), 0x1000);
+ const events: ITestEvent[] = [];
+ for (const i of [10, 4, 1]) {
+ cpu.addClockEvent(() => events.push([i, cpu.cycles]), i);
+ }
+ for (let i = 0; i < 10; i++) {
+ cpu.cycles++;
+ cpu.tick();
+ }
+ expect(events).toEqual([
+ [1, 1],
+ [4, 4],
+ [10, 10],
+ ]);
+ });
+
describe('updateClockEvent', () => {
it('should update the number of cycles for the given clock event', () => {
const cpu = new CPU(new Uint16Array(1024), 0x1000);
@@ -65,6 +82,20 @@ describe('cpu', () => {
[10, 10],
]);
});
+
+ it('should return false if the provided clock event is not scheduled', () => {
+ const cpu = new CPU(new Uint16Array(1024), 0x1000);
+ const event4 = cpu.addClockEvent(() => 0, 4);
+ const event10 = cpu.addClockEvent(() => 0, 10);
+ cpu.addClockEvent(() => 0, 1);
+
+ // Both event should be successfully removed
+ expect(cpu.clearClockEvent(event4)).toBe(true);
+ expect(cpu.clearClockEvent(event10)).toBe(true);
+ // And now we should get false, as these events have already been removed
+ expect(cpu.clearClockEvent(event4)).toBe(false);
+ expect(cpu.clearClockEvent(event10)).toBe(false);
+ });
});
});
});
diff --git a/src/cpu/cpu.ts b/src/cpu/cpu.ts
index e7a2544..a609222 100644
--- a/src/cpu/cpu.ts
+++ b/src/cpu/cpu.ts
@@ -173,23 +173,29 @@ export class CPU implements ICPU {
}
}
- private updateClockEvents() {
- this.clockEvents.sort((a, b) => a.cycles - b.cycles);
- this.nextClockEvent = this.clockEvents[0]?.cycles ?? 0;
- }
-
addClockEvent(callback: AVRClockEventCallback, cycles: number) {
const entry = { cycles: this.cycles + Math.max(1, cycles), callback };
- this.clockEvents.push(entry);
- this.updateClockEvents();
+ // Add the new entry while keeping the array sorted
+ const { clockEvents } = this;
+ if (!clockEvents.length || clockEvents[clockEvents.length - 1].cycles <= entry.cycles) {
+ clockEvents.push(entry);
+ } else if (clockEvents[0].cycles >= entry.cycles) {
+ clockEvents.unshift(entry);
+ } else {
+ for (let i = 1; i < clockEvents.length; i++) {
+ if (clockEvents[i].cycles >= entry.cycles) {
+ clockEvents.splice(i, 0, entry);
+ break;
+ }
+ }
+ }
+ this.nextClockEvent = this.clockEvents[0].cycles;
return callback;
}
updateClockEvent(callback: AVRClockEventCallback, cycles: number) {
- const entry = this.clockEvents.find((item) => item.callback === callback);
- if (entry) {
- entry.cycles = this.cycles + Math.max(1, cycles);
- this.updateClockEvents();
+ if (this.clearClockEvent(callback)) {
+ this.addClockEvent(callback, cycles);
return true;
}
return false;
@@ -199,18 +205,22 @@ export class CPU implements ICPU {
const index = this.clockEvents.findIndex((item) => item.callback === callback);
if (index >= 0) {
this.clockEvents.splice(index, 1);
- this.updateClockEvents();
+ this.nextClockEvent = this.clockEvents[0]?.cycles ?? 0;
+ return true;
}
+ return false;
}
tick() {
- if (this.nextClockEvent && this.nextClockEvent <= this.cycles) {
- const clockEvent = this.clockEvents.shift();
- clockEvent?.callback();
- this.nextClockEvent = this.clockEvents[0]?.cycles ?? 0;
+ const { nextClockEvent, clockEvents } = this;
+ if (nextClockEvent && nextClockEvent <= this.cycles) {
+ clockEvents.shift()?.callback();
+ this.nextClockEvent = clockEvents[0]?.cycles ?? 0;
}
- if (this.interruptsEnabled && this.nextInterrupt >= 0) {
- const interrupt = this.pendingInterrupts[this.nextInterrupt];
+
+ const { nextInterrupt } = this;
+ if (this.interruptsEnabled && nextInterrupt >= 0) {
+ const interrupt = this.pendingInterrupts[nextInterrupt];
avrInterrupt(this, interrupt.address);
if (!interrupt.constant) {
this.clearInterrupt(interrupt);
If you find this content useful please consider a small donation via bitcoin: bitcoin:1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2?amount=0.001&message=Donation Scraping git contents via cgit is very resource intensive. The continued hosting of these git repositories is entirely financed by your bitcoin contributions. For donations of a least 1 mBTC you include your IP address in the message of your bitcoin donation. This will remove this message in the future for requests from your IP, which will significantly reduce token usage. In any case, any contributions to bitcoin address 1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2 are very welcome. Thanks in advance for you contribution to a self-sustaining ecosystem.