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<
- +