diff --git a/page/src/components/emulation-summary.tsx b/page/src/components/emulation-summary.tsx
index 71aeee6e..5cac2329 100644
--- a/page/src/components/emulation-summary.tsx
+++ b/page/src/components/emulation-summary.tsx
@@ -1,6 +1,6 @@
import { EmulationStatus } from "@/emulator";
import { TextTooltip } from "./text-tooltip";
-import { BarChartSteps, CpuFill } from "react-bootstrap-icons";
+import { BarChartSteps, CpuFill, FloppyFill } from "react-bootstrap-icons";
import "./emulation-summary.css";
@@ -8,6 +8,20 @@ export interface EmulationSummaryProps {
status?: EmulationStatus;
}
+function formatMemory(value: BigInt): string {
+ const abbr = ["B", "KB", "MB", "GB", "PB"];
+
+ let num = Number(value);
+ let index = 0;
+
+ while (num >= 1024 && index < abbr.length - 1) {
+ num /= 1024;
+ index++;
+ }
+
+ return num.toFixed(2) + " " + abbr[index];
+}
+
export function EmulationSummary(props: EmulationSummaryProps) {
if (!props.status) {
return <>>;
@@ -20,6 +34,11 @@ export function EmulationSummary(props: EmulationSummaryProps) {
+
+ {formatMemory(props.status.committedMemory)}
+
+
+
{props.status.executedInstructions.toLocaleString()}
diff --git a/page/src/emulator.ts b/page/src/emulator.ts
index c26b9fa5..230b55f5 100644
--- a/page/src/emulator.ts
+++ b/page/src/emulator.ts
@@ -14,14 +14,18 @@ export enum EmulationState {
}
export interface EmulationStatus {
- executedInstructions: BigInt;
activeThreads: number;
+ reservedMemory: BigInt;
+ committedMemory: BigInt;
+ executedInstructions: BigInt;
}
function createDefaultEmulationStatus(): EmulationStatus {
return {
executedInstructions: BigInt(0),
activeThreads: 0,
+ reservedMemory: BigInt(0),
+ committedMemory: BigInt(0),
};
}
@@ -239,6 +243,8 @@ export class Emulator {
this.stautsUpdateHandler({
activeThreads: info.activeThreads,
executedInstructions: info.executedInstructions,
+ reservedMemory: info.reservedMemory,
+ committedMemory: info.committedMemory,
});
}
diff --git a/page/src/fb/debugger/emulation-status.ts b/page/src/fb/debugger/emulation-status.ts
index 1d86bda4..6a3be671 100644
--- a/page/src/fb/debugger/emulation-status.ts
+++ b/page/src/fb/debugger/emulation-status.ts
@@ -24,29 +24,13 @@ static getSizePrefixedRootAsEmulationStatus(bb:flatbuffers.ByteBuffer, obj?:Emul
return (obj || new EmulationStatus()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
-executedInstructions():bigint {
- const offset = this.bb!.__offset(this.bb_pos, 4);
- return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
-}
-
-mutate_executed_instructions(value:bigint):boolean {
- const offset = this.bb!.__offset(this.bb_pos, 4);
-
- if (offset === 0) {
- return false;
- }
-
- this.bb!.writeUint64(this.bb_pos + offset, value);
- return true;
-}
-
activeThreads():number {
- const offset = this.bb!.__offset(this.bb_pos, 6);
+ const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
}
mutate_active_threads(value:number):boolean {
- const offset = this.bb!.__offset(this.bb_pos, 6);
+ const offset = this.bb!.__offset(this.bb_pos, 4);
if (offset === 0) {
return false;
@@ -56,16 +40,72 @@ mutate_active_threads(value:number):boolean {
return true;
}
-static startEmulationStatus(builder:flatbuffers.Builder) {
- builder.startObject(2);
+reservedMemory():bigint {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
-static addExecutedInstructions(builder:flatbuffers.Builder, executedInstructions:bigint) {
- builder.addFieldInt64(0, executedInstructions, BigInt('0'));
+mutate_reserved_memory(value:bigint):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+}
+
+committedMemory():bigint {
+ const offset = this.bb!.__offset(this.bb_pos, 8);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
+}
+
+mutate_committed_memory(value:bigint):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 8);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+}
+
+executedInstructions():bigint {
+ const offset = this.bb!.__offset(this.bb_pos, 10);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
+}
+
+mutate_executed_instructions(value:bigint):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 10);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+}
+
+static startEmulationStatus(builder:flatbuffers.Builder) {
+ builder.startObject(4);
}
static addActiveThreads(builder:flatbuffers.Builder, activeThreads:number) {
- builder.addFieldInt32(1, activeThreads, 0);
+ builder.addFieldInt32(0, activeThreads, 0);
+}
+
+static addReservedMemory(builder:flatbuffers.Builder, reservedMemory:bigint) {
+ builder.addFieldInt64(1, reservedMemory, BigInt('0'));
+}
+
+static addCommittedMemory(builder:flatbuffers.Builder, committedMemory:bigint) {
+ builder.addFieldInt64(2, committedMemory, BigInt('0'));
+}
+
+static addExecutedInstructions(builder:flatbuffers.Builder, executedInstructions:bigint) {
+ builder.addFieldInt64(3, executedInstructions, BigInt('0'));
}
static endEmulationStatus(builder:flatbuffers.Builder):flatbuffers.Offset {
@@ -73,38 +113,48 @@ static endEmulationStatus(builder:flatbuffers.Builder):flatbuffers.Offset {
return offset;
}
-static createEmulationStatus(builder:flatbuffers.Builder, executedInstructions:bigint, activeThreads:number):flatbuffers.Offset {
+static createEmulationStatus(builder:flatbuffers.Builder, activeThreads:number, reservedMemory:bigint, committedMemory:bigint, executedInstructions:bigint):flatbuffers.Offset {
EmulationStatus.startEmulationStatus(builder);
- EmulationStatus.addExecutedInstructions(builder, executedInstructions);
EmulationStatus.addActiveThreads(builder, activeThreads);
+ EmulationStatus.addReservedMemory(builder, reservedMemory);
+ EmulationStatus.addCommittedMemory(builder, committedMemory);
+ EmulationStatus.addExecutedInstructions(builder, executedInstructions);
return EmulationStatus.endEmulationStatus(builder);
}
unpack(): EmulationStatusT {
return new EmulationStatusT(
- this.executedInstructions(),
- this.activeThreads()
+ this.activeThreads(),
+ this.reservedMemory(),
+ this.committedMemory(),
+ this.executedInstructions()
);
}
unpackTo(_o: EmulationStatusT): void {
- _o.executedInstructions = this.executedInstructions();
_o.activeThreads = this.activeThreads();
+ _o.reservedMemory = this.reservedMemory();
+ _o.committedMemory = this.committedMemory();
+ _o.executedInstructions = this.executedInstructions();
}
}
export class EmulationStatusT implements flatbuffers.IGeneratedObject {
constructor(
- public executedInstructions: bigint = BigInt('0'),
- public activeThreads: number = 0
+ public activeThreads: number = 0,
+ public reservedMemory: bigint = BigInt('0'),
+ public committedMemory: bigint = BigInt('0'),
+ public executedInstructions: bigint = BigInt('0')
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return EmulationStatus.createEmulationStatus(builder,
- this.executedInstructions,
- this.activeThreads
+ this.activeThreads,
+ this.reservedMemory,
+ this.committedMemory,
+ this.executedInstructions
);
}
}
diff --git a/src/debugger/event_handler.cpp b/src/debugger/event_handler.cpp
index 8fc26b56..1fbaee81 100644
--- a/src/debugger/event_handler.cpp
+++ b/src/debugger/event_handler.cpp
@@ -236,7 +236,11 @@ namespace debugger
void update_emulation_status(const windows_emulator& win_emu)
{
+ const auto memory_status = win_emu.memory.compute_memory_stats();
+
Debugger::EmulationStatusT status{};
+ status.reserved_memory = memory_status.reserved_memory;
+ status.committed_memory = memory_status.committed_memory;
status.executed_instructions = win_emu.get_executed_instructions();
status.active_threads = static_cast(win_emu.process.threads.size());
send_event(status);
diff --git a/src/debugger/events.fbs b/src/debugger/events.fbs
index fd4c1d48..8eca5b13 100644
--- a/src/debugger/events.fbs
+++ b/src/debugger/events.fbs
@@ -64,8 +64,10 @@ table ApplicationExit {
}
table EmulationStatus {
- executed_instructions: uint64;
active_threads: uint32;
+ reserved_memory: uint64;
+ committed_memory: uint64;
+ executed_instructions: uint64;
}
union Event {
diff --git a/src/debugger/events_generated.hxx b/src/debugger/events_generated.hxx
index 049b45ba..c7f098b3 100644
--- a/src/debugger/events_generated.hxx
+++ b/src/debugger/events_generated.hxx
@@ -1303,33 +1303,51 @@ inline ::flatbuffers::Offset CreateApplicationExit(
struct EmulationStatusT : public ::flatbuffers::NativeTable {
typedef EmulationStatus TableType;
- uint64_t executed_instructions = 0;
uint32_t active_threads = 0;
+ uint64_t reserved_memory = 0;
+ uint64_t committed_memory = 0;
+ uint64_t executed_instructions = 0;
};
struct EmulationStatus FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
typedef EmulationStatusT NativeTableType;
typedef EmulationStatusBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
- VT_EXECUTED_INSTRUCTIONS = 4,
- VT_ACTIVE_THREADS = 6
+ VT_ACTIVE_THREADS = 4,
+ VT_RESERVED_MEMORY = 6,
+ VT_COMMITTED_MEMORY = 8,
+ VT_EXECUTED_INSTRUCTIONS = 10
};
- uint64_t executed_instructions() const {
- return GetField(VT_EXECUTED_INSTRUCTIONS, 0);
- }
- bool mutate_executed_instructions(uint64_t _executed_instructions = 0) {
- return SetField(VT_EXECUTED_INSTRUCTIONS, _executed_instructions, 0);
- }
uint32_t active_threads() const {
return GetField(VT_ACTIVE_THREADS, 0);
}
bool mutate_active_threads(uint32_t _active_threads = 0) {
return SetField(VT_ACTIVE_THREADS, _active_threads, 0);
}
+ uint64_t reserved_memory() const {
+ return GetField(VT_RESERVED_MEMORY, 0);
+ }
+ bool mutate_reserved_memory(uint64_t _reserved_memory = 0) {
+ return SetField(VT_RESERVED_MEMORY, _reserved_memory, 0);
+ }
+ uint64_t committed_memory() const {
+ return GetField(VT_COMMITTED_MEMORY, 0);
+ }
+ bool mutate_committed_memory(uint64_t _committed_memory = 0) {
+ return SetField(VT_COMMITTED_MEMORY, _committed_memory, 0);
+ }
+ uint64_t executed_instructions() const {
+ return GetField(VT_EXECUTED_INSTRUCTIONS, 0);
+ }
+ bool mutate_executed_instructions(uint64_t _executed_instructions = 0) {
+ return SetField(VT_EXECUTED_INSTRUCTIONS, _executed_instructions, 0);
+ }
bool Verify(::flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
- VerifyField(verifier, VT_EXECUTED_INSTRUCTIONS, 8) &&
VerifyField(verifier, VT_ACTIVE_THREADS, 4) &&
+ VerifyField(verifier, VT_RESERVED_MEMORY, 8) &&
+ VerifyField(verifier, VT_COMMITTED_MEMORY, 8) &&
+ VerifyField(verifier, VT_EXECUTED_INSTRUCTIONS, 8) &&
verifier.EndTable();
}
EmulationStatusT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
@@ -1341,12 +1359,18 @@ struct EmulationStatusBuilder {
typedef EmulationStatus Table;
::flatbuffers::FlatBufferBuilder &fbb_;
::flatbuffers::uoffset_t start_;
- void add_executed_instructions(uint64_t executed_instructions) {
- fbb_.AddElement(EmulationStatus::VT_EXECUTED_INSTRUCTIONS, executed_instructions, 0);
- }
void add_active_threads(uint32_t active_threads) {
fbb_.AddElement(EmulationStatus::VT_ACTIVE_THREADS, active_threads, 0);
}
+ void add_reserved_memory(uint64_t reserved_memory) {
+ fbb_.AddElement(EmulationStatus::VT_RESERVED_MEMORY, reserved_memory, 0);
+ }
+ void add_committed_memory(uint64_t committed_memory) {
+ fbb_.AddElement(EmulationStatus::VT_COMMITTED_MEMORY, committed_memory, 0);
+ }
+ void add_executed_instructions(uint64_t executed_instructions) {
+ fbb_.AddElement(EmulationStatus::VT_EXECUTED_INSTRUCTIONS, executed_instructions, 0);
+ }
explicit EmulationStatusBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
@@ -1360,10 +1384,14 @@ struct EmulationStatusBuilder {
inline ::flatbuffers::Offset CreateEmulationStatus(
::flatbuffers::FlatBufferBuilder &_fbb,
- uint64_t executed_instructions = 0,
- uint32_t active_threads = 0) {
+ uint32_t active_threads = 0,
+ uint64_t reserved_memory = 0,
+ uint64_t committed_memory = 0,
+ uint64_t executed_instructions = 0) {
EmulationStatusBuilder builder_(_fbb);
builder_.add_executed_instructions(executed_instructions);
+ builder_.add_committed_memory(committed_memory);
+ builder_.add_reserved_memory(reserved_memory);
builder_.add_active_threads(active_threads);
return builder_.Finish();
}
@@ -1903,8 +1931,10 @@ inline EmulationStatusT *EmulationStatus::UnPack(const ::flatbuffers::resolver_f
inline void EmulationStatus::UnPackTo(EmulationStatusT *_o, const ::flatbuffers::resolver_function_t *_resolver) const {
(void)_o;
(void)_resolver;
- { auto _e = executed_instructions(); _o->executed_instructions = _e; }
{ auto _e = active_threads(); _o->active_threads = _e; }
+ { auto _e = reserved_memory(); _o->reserved_memory = _e; }
+ { auto _e = committed_memory(); _o->committed_memory = _e; }
+ { auto _e = executed_instructions(); _o->executed_instructions = _e; }
}
inline ::flatbuffers::Offset EmulationStatus::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const EmulationStatusT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) {
@@ -1915,12 +1945,16 @@ inline ::flatbuffers::Offset CreateEmulationStatus(::flatbuffer
(void)_rehasher;
(void)_o;
struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const EmulationStatusT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
- auto _executed_instructions = _o->executed_instructions;
auto _active_threads = _o->active_threads;
+ auto _reserved_memory = _o->reserved_memory;
+ auto _committed_memory = _o->committed_memory;
+ auto _executed_instructions = _o->executed_instructions;
return Debugger::CreateEmulationStatus(
_fbb,
- _executed_instructions,
- _active_threads);
+ _active_threads,
+ _reserved_memory,
+ _committed_memory,
+ _executed_instructions);
}
inline DebugEventT *DebugEvent::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const {
diff --git a/src/windows-emulator/memory_manager.cpp b/src/windows-emulator/memory_manager.cpp
index 98268bef..82c9cb42 100644
--- a/src/windows-emulator/memory_manager.cpp
+++ b/src/windows-emulator/memory_manager.cpp
@@ -100,6 +100,25 @@ void memory_manager::update_layout_version()
#endif
}
+memory_stats memory_manager::compute_memory_stats() const
+{
+ memory_stats stats{};
+ stats.reserved_memory = 0;
+ stats.committed_memory = 0;
+
+ for (const auto& reserved_region : this->reserved_regions_ | std::views::values)
+ {
+ stats.reserved_memory += reserved_region.length;
+
+ for (const auto& committed_region : reserved_region.committed_regions | std::views::values)
+ {
+ stats.committed_memory += committed_region.length;
+ }
+ }
+
+ return stats;
+}
+
void memory_manager::serialize_memory_state(utils::buffer_serializer& buffer, const bool is_snapshot) const
{
buffer.write_atomic(this->layout_version_);
diff --git a/src/windows-emulator/memory_manager.hpp b/src/windows-emulator/memory_manager.hpp
index 4b5f087e..b490ee23 100644
--- a/src/windows-emulator/memory_manager.hpp
+++ b/src/windows-emulator/memory_manager.hpp
@@ -24,6 +24,12 @@ struct region_info : basic_memory_region
using mmio_read_callback = std::function;
using mmio_write_callback = std::function;
+struct memory_stats
+{
+ uint64_t reserved_memory = 0;
+ uint64_t committed_memory = 0;
+};
+
class memory_manager : public memory_interface
{
public:
@@ -90,6 +96,8 @@ class memory_manager : public memory_interface
void serialize_memory_state(utils::buffer_serializer& buffer, bool is_snapshot) const;
void deserialize_memory_state(utils::buffer_deserializer& buffer, bool is_snapshot);
+ memory_stats compute_memory_stats() const;
+
private:
memory_interface* memory_{};
reserved_region_map reserved_regions_{};