diff --git a/page/src/components/emulation-summary.tsx b/page/src/components/emulation-summary.tsx
index 8a233c3b..e98adfe4 100644
--- a/page/src/components/emulation-summary.tsx
+++ b/page/src/components/emulation-summary.tsx
@@ -1,9 +1,16 @@
import { EmulationStatus } from "@/emulator";
import { TextTooltip } from "./text-tooltip";
-import { BarChartSteps, CpuFill, FloppyFill } from "react-bootstrap-icons";
+import {
+ BarChartSteps,
+ CpuFill,
+ FloppyFill,
+ StopwatchFill,
+} from "react-bootstrap-icons";
+import React from "react";
export interface EmulationSummaryProps {
status?: EmulationStatus;
+ executionTimeFetcher: () => number;
}
function formatMemory(value: BigInt): string {
@@ -20,27 +27,75 @@ function formatMemory(value: BigInt): string {
return num.toFixed(2) + " " + abbr[index];
}
-export function EmulationSummary(props: EmulationSummaryProps) {
- if (!props.status) {
- return <>>;
+function formatTime(seconds: number): string {
+ const hrs = Math.floor(seconds / 3600);
+ const mins = Math.floor((seconds % 3600) / 60);
+ const secs = Math.floor(seconds % 60);
+
+ const secsString = secs < 10 ? "0" + secs : secs.toString();
+
+ if (hrs > 0) {
+ const minsString = mins < 10 ? "0" + mins : mins.toString();
+ return `${hrs.toString()}:${minsString}:${secsString}`;
}
- return (
-
-
- {props.status.activeThreads}
-
-
-
-
- {formatMemory(props.status.committedMemory)}
-
-
-
-
- {props.status.executedInstructions.toLocaleString()}
-
-
-
- );
+ return `${mins.toString()}:${secsString}`;
+}
+
+export class EmulationSummary extends React.Component<
+ EmulationSummaryProps,
+ {}
+> {
+ private timer: NodeJS.Timeout | undefined = undefined;
+
+ constructor(props: EmulationSummaryProps) {
+ super(props);
+ }
+
+ componentDidMount(): void {
+ if (this.timer) {
+ clearInterval(this.timer);
+ }
+
+ this.timer = setInterval(() => {
+ this.forceUpdate();
+ }, 200);
+ }
+
+ componentWillUnmount(): void {
+ if (this.timer) {
+ clearInterval(this.timer);
+ this.timer = undefined;
+ }
+ }
+
+ render() {
+ if (!this.props.status) {
+ return <>>;
+ }
+
+ return (
+
+
+ {this.props.status.activeThreads}
+
+
+
+
+ {formatMemory(this.props.status.committedMemory)}
+
+
+
+
+ {this.props.status.executedInstructions.toLocaleString()}
+
+
+
+
+ {formatTime(this.props.executionTimeFetcher() / 1000)}
+
+
+
+ );
+ }
}
diff --git a/page/src/emulator.ts b/page/src/emulator.ts
index 8619f9af..b2bdba87 100644
--- a/page/src/emulator.ts
+++ b/page/src/emulator.ts
@@ -85,6 +85,9 @@ export class Emulator {
worker: Worker;
state: EmulationState = EmulationState.Stopped;
exit_status: number | null = null;
+ start_time: Date = new Date();
+ pause_time: Date | null = null;
+ paused_time: number = 0;
constructor(
logHandler: LogHandler,
@@ -109,6 +112,9 @@ export class Emulator {
}
async start(settings: Settings, file: string) {
+ this.start_time = new Date();
+ this.pause_time = null;
+ this.paused_time = 0;
this._setState(EmulationState.Running);
this.stautsUpdateHandler(createDefaultEmulationStatus());
@@ -184,6 +190,12 @@ export class Emulator {
this.updateState();
}
+ getExecutionTime() {
+ const endTime = this.pause_time ? this.pause_time : new Date();
+ const totalTime = endTime.getTime() - this.start_time.getTime();
+ return totalTime - this.paused_time;
+ }
+
logError(message: string) {
this.logHandler([`${message}`]);
}
@@ -233,6 +245,14 @@ export class Emulator {
_setState(state: EmulationState) {
this.state = state;
+
+ if (isFinalState(this.state) || this.state === EmulationState.Paused) {
+ this.pause_time = new Date();
+ } else if (this.state == EmulationState.Running && this.pause_time) {
+ this.paused_time += new Date().getTime() - this.pause_time.getTime();
+ this.pause_time = null;
+ }
+
this.stateChangeHandler(this.state);
}
diff --git a/page/src/playground.tsx b/page/src/playground.tsx
index d3171873..885bc4c7 100644
--- a/page/src/playground.tsx
+++ b/page/src/playground.tsx
@@ -130,6 +130,7 @@ export class Playground extends React.Component<
this.start = this.start.bind(this);
this.resetFilesys = this.resetFilesys.bind(this);
this.startEmulator = this.startEmulator.bind(this);
+ this.fetchExecutionTime = this.fetchExecutionTime.bind(this);
this.toggleEmulatorState = this.toggleEmulatorState.bind(this);
this.state = {
@@ -162,6 +163,10 @@ export class Playground extends React.Component<
});
}
+ fetchExecutionTime() {
+ return this.state.emulator ? this.state.emulator.getExecutionTime() : 0;
+ }
+
async resetFilesys() {
if (!this.state.filesystem) {
return;
@@ -440,7 +445,10 @@ export class Playground extends React.Component<