From 08995a42059d5ddf97c6ee6305f2fc924342b35d Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 12 Jul 2025 13:47:52 +0200 Subject: [PATCH] Print memory stats --- page/src/components/emulation-summary.tsx | 21 +++- page/src/emulator.ts | 8 +- page/src/fb/debugger/emulation-status.ts | 114 ++++++++++++++++------ src/debugger/event_handler.cpp | 4 + src/debugger/events.fbs | 4 +- src/debugger/events_generated.hxx | 72 ++++++++++---- src/windows-emulator/memory_manager.cpp | 19 ++++ src/windows-emulator/memory_manager.hpp | 8 ++ 8 files changed, 196 insertions(+), 54 deletions(-) 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_{};