1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 02:37:35 +00:00

UserspaceEmulator: Move all the profiling details into the Emulator

Them being in the global namespace doesn't have a lot of fans, it seems.
This commit is contained in:
Ali Mohammad Pur 2021-08-08 15:28:07 +04:30 committed by Ali Mohammad Pur
parent 2128ae4ab0
commit 369e3da6a2
4 changed files with 55 additions and 42 deletions

View file

@ -27,11 +27,6 @@
# pragma GCC optimize("O3") # pragma GCC optimize("O3")
#endif #endif
extern bool g_dump_profile;
extern unsigned g_profile_instruction_interval;
extern Optional<OutputFileStream> g_profile_stream;
extern bool g_in_region_of_interest;
namespace UserspaceEmulator { namespace UserspaceEmulator {
static constexpr u32 stack_location = 0x10000000; static constexpr u32 stack_location = 0x10000000;
@ -224,9 +219,9 @@ int Emulator::exec()
constexpr bool trace = false; constexpr bool trace = false;
size_t instructions_until_next_profile_dump = g_profile_instruction_interval; size_t instructions_until_next_profile_dump = profile_instruction_interval();
if (g_dump_profile && m_loader_text_size.has_value()) if (is_profiling() && m_loader_text_size.has_value())
emit_profile_event(*g_profile_stream, "mmap", String::formatted(R"("ptr": {}, "size": {}, "name": "/usr/lib/Loader.so")", *m_loader_text_base, *m_loader_text_size)); emit_profile_event(profile_stream(), "mmap", String::formatted(R"("ptr": {}, "size": {}, "name": "/usr/lib/Loader.so")", *m_loader_text_base, *m_loader_text_size));
while (!m_shutdown) { while (!m_shutdown) {
if (m_steps_til_pause) [[likely]] { if (m_steps_til_pause) [[likely]] {
@ -239,10 +234,10 @@ int Emulator::exec()
(m_cpu.*insn.handler())(insn); (m_cpu.*insn.handler())(insn);
if (g_dump_profile) { if (is_profiling()) {
if (instructions_until_next_profile_dump == 0) { if (instructions_until_next_profile_dump == 0) {
instructions_until_next_profile_dump = g_profile_instruction_interval; instructions_until_next_profile_dump = profile_instruction_interval();
emit_profile_sample(*g_profile_stream); emit_profile_sample(profile_stream());
} else { } else {
--instructions_until_next_profile_dump; --instructions_until_next_profile_dump;
} }
@ -474,7 +469,7 @@ void Emulator::dump_backtrace()
void Emulator::emit_profile_sample(AK::OutputStream& output) void Emulator::emit_profile_sample(AK::OutputStream& output)
{ {
if (!g_in_region_of_interest) if (!is_in_region_of_interest())
return; return;
StringBuilder builder; StringBuilder builder;
timeval tv {}; timeval tv {};

View file

@ -12,6 +12,7 @@
#include "Report.h" #include "Report.h"
#include "SoftCPU.h" #include "SoftCPU.h"
#include "SoftMMU.h" #include "SoftMMU.h"
#include <AK/FileStream.h>
#include <AK/MappedFile.h> #include <AK/MappedFile.h>
#include <AK/Types.h> #include <AK/Types.h>
#include <LibDebug/DebugInfo.h> #include <LibDebug/DebugInfo.h>
@ -32,6 +33,23 @@ public:
Emulator(String const& executable_path, Vector<String> const& arguments, Vector<String> const& environment); Emulator(String const& executable_path, Vector<String> const& arguments, Vector<String> const& environment);
void set_profiling_details(bool should_dump_profile, size_t instruction_interval, OutputFileStream* profile_stream)
{
m_is_profiling = should_dump_profile;
m_profile_instruction_interval = instruction_interval;
m_profile_stream = profile_stream;
}
void set_in_region_of_interest(bool value)
{
m_is_in_region_of_interest = value;
}
OutputFileStream& profile_stream() { return *m_profile_stream; }
bool is_profiling() const { return m_is_profiling; }
bool is_in_region_of_interest() const { return m_is_in_region_of_interest; }
size_t profile_instruction_interval() const { return m_profile_instruction_interval; }
bool load_elf(); bool load_elf();
void dump_backtrace(); void dump_backtrace();
void dump_backtrace(Vector<FlatPtr> const&); void dump_backtrace(Vector<FlatPtr> const&);
@ -271,6 +289,11 @@ private:
HashMap<String, CachedELF> m_dynamic_library_cache; HashMap<String, CachedELF> m_dynamic_library_cache;
RangeAllocator m_range_allocator; RangeAllocator m_range_allocator;
OutputFileStream* m_profile_stream { nullptr };
bool m_is_profiling { false };
size_t m_profile_instruction_interval { 0 };
bool m_is_in_region_of_interest { false };
}; };
ALWAYS_INLINE bool Emulator::is_in_libc() const ALWAYS_INLINE bool Emulator::is_in_libc() const

View file

@ -28,10 +28,6 @@
# pragma GCC optimize("O3") # pragma GCC optimize("O3")
#endif #endif
extern bool g_dump_profile;
extern Optional<OutputFileStream> g_profile_stream;
extern bool g_in_region_of_interest;
namespace UserspaceEmulator { namespace UserspaceEmulator {
u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3) u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3)
@ -817,8 +813,8 @@ static void round_to_page_size(FlatPtr& address, size_t& size)
u32 Emulator::virt$munmap(FlatPtr address, size_t size) u32 Emulator::virt$munmap(FlatPtr address, size_t size)
{ {
if (g_dump_profile) if (is_profiling())
emit_profile_event(*g_profile_stream, "munmap", String::formatted("\"ptr\": {}, \"size\": {}", address, size)); emit_profile_event(profile_stream(), "munmap", String::formatted("\"ptr\": {}, \"size\": {}", address, size));
round_to_page_size(address, size); round_to_page_size(address, size);
Vector<Region*, 4> marked_for_deletion; Vector<Region*, 4> marked_for_deletion;
bool has_non_mmap_region = false; bool has_non_mmap_region = false;
@ -877,8 +873,8 @@ u32 Emulator::virt$mmap(u32 params_addr)
name_str = { name.data(), name.size() }; name_str = { name.data(), name.size() };
} }
if (g_dump_profile) if (is_profiling())
emit_profile_event(*g_profile_stream, "mmap", String::formatted(R"("ptr": {}, "size": {}, "name": "{}")", final_address, final_size, name_str)); emit_profile_event(profile_stream(), "mmap", String::formatted(R"("ptr": {}, "size": {}, "name": "{}")", final_address, final_size, name_str));
if (params.flags & MAP_ANONYMOUS) { if (params.flags & MAP_ANONYMOUS) {
mmu().add_region(MmapRegion::create_anonymous(final_address, final_size, params.prot, move(name_str))); mmu().add_region(MmapRegion::create_anonymous(final_address, final_size, params.prot, move(name_str)));
@ -1135,12 +1131,12 @@ int Emulator::virt$emuctl(FlatPtr arg1, FlatPtr arg2, FlatPtr arg3)
tracer->target_did_change_chunk_size({}, arg3, arg2); tracer->target_did_change_chunk_size({}, arg3, arg2);
return 0; return 0;
case 5: // mark ROI start case 5: // mark ROI start
if (g_in_region_of_interest) if (is_in_region_of_interest())
return -EINVAL; return -EINVAL;
g_in_region_of_interest = true; m_is_in_region_of_interest = true;
return 0; return 0;
case 6: // mark ROI end case 6: // mark ROI end
g_in_region_of_interest = false; m_is_in_region_of_interest = false;
return 0; return 0;
default: default:
return -EINVAL; return -EINVAL;

View file

@ -18,10 +18,6 @@
#include <string.h> #include <string.h>
bool g_report_to_debug = false; bool g_report_to_debug = false;
bool g_in_region_of_interest = true;
bool g_dump_profile = false;
unsigned g_profile_instruction_interval = 0;
Optional<OutputFileStream> g_profile_stream;
int main(int argc, char** argv, char** env) int main(int argc, char** argv, char** env)
{ {
@ -30,13 +26,15 @@ int main(int argc, char** argv, char** env)
String profile_dump_path; String profile_dump_path;
FILE* profile_output_file { nullptr }; FILE* profile_output_file { nullptr };
bool enable_roi_mode { false }; bool enable_roi_mode { false };
bool dump_profile { false };
unsigned profile_instruction_interval { 0 };
Core::ArgsParser parser; Core::ArgsParser parser;
parser.set_stop_on_first_non_option(true); parser.set_stop_on_first_non_option(true);
parser.add_option(g_report_to_debug, "Write reports to the debug log", "report-to-debug", 0); parser.add_option(g_report_to_debug, "Write reports to the debug log", "report-to-debug", 0);
parser.add_option(pause_on_startup, "Pause on startup", "pause", 'p'); parser.add_option(pause_on_startup, "Pause on startup", "pause", 'p');
parser.add_option(g_dump_profile, "Generate a ProfileViewer-compatible profile", "profile", 0); parser.add_option(dump_profile, "Generate a ProfileViewer-compatible profile", "profile", 0);
parser.add_option(g_profile_instruction_interval, "Set the profile instruction capture interval, 128 by default", "profile-interval", 'i', "#instructions"); parser.add_option(profile_instruction_interval, "Set the profile instruction capture interval, 128 by default", "profile-interval", 'i', "#instructions");
parser.add_option(profile_dump_path, "File path for profile dump", "profile-file", 0, "path"); parser.add_option(profile_dump_path, "File path for profile dump", "profile-file", 0, "path");
parser.add_option(enable_roi_mode, "Enable Region-of-Interest mode for profiling", "roi", 0); parser.add_option(enable_roi_mode, "Enable Region-of-Interest mode for profiling", "roi", 0);
@ -44,11 +42,8 @@ int main(int argc, char** argv, char** env)
parser.parse(argc, argv); parser.parse(argc, argv);
if (g_dump_profile && g_profile_instruction_interval == 0) if (dump_profile && profile_instruction_interval == 0)
g_profile_instruction_interval = 128; profile_instruction_interval = 128;
if (enable_roi_mode)
g_in_region_of_interest = false;
String executable_path; String executable_path;
if (arguments[0].contains("/"sv)) if (arguments[0].contains("/"sv))
@ -60,22 +55,23 @@ int main(int argc, char** argv, char** env)
return 1; return 1;
} }
if (g_dump_profile && profile_dump_path.is_empty()) if (dump_profile && profile_dump_path.is_empty())
profile_dump_path = String::formatted("{}.{}.profile", executable_path, getpid()); profile_dump_path = String::formatted("{}.{}.profile", executable_path, getpid());
if (g_dump_profile) { OwnPtr<OutputFileStream> profile_stream;
if (dump_profile) {
profile_output_file = fopen(profile_dump_path.characters(), "w+"); profile_output_file = fopen(profile_dump_path.characters(), "w+");
if (profile_output_file == nullptr) { if (profile_output_file == nullptr) {
auto error_string = strerror(errno); auto error_string = strerror(errno);
warnln("Failed to open '{}' for writing: {}", profile_dump_path, error_string); warnln("Failed to open '{}' for writing: {}", profile_dump_path, error_string);
return 1; return 1;
} }
g_profile_stream = OutputFileStream { profile_output_file }; profile_stream = make<OutputFileStream>(profile_output_file);
g_profile_stream->write_or_error(R"({"events":[)"sv.bytes()); profile_stream->write_or_error(R"({"events":[)"sv.bytes());
timeval tv {}; timeval tv {};
gettimeofday(&tv, nullptr); gettimeofday(&tv, nullptr);
g_profile_stream->write_or_error( profile_stream->write_or_error(
String::formatted( String::formatted(
R"~({{"type": "process_create", "parent_pid": 1, "executable": "{}", "pid": {}, "tid": {}, "timestamp": {}, "lost_samples": 0, "stack": []}})~", R"~({{"type": "process_create", "parent_pid": 1, "executable": "{}", "pid": {}, "tid": {}, "timestamp": {}, "lost_samples": 0, "stack": []}})~",
executable_path, getpid(), gettid(), tv.tv_sec * 1000 + tv.tv_usec / 1000) executable_path, getpid(), gettid(), tv.tv_sec * 1000 + tv.tv_usec / 1000)
@ -89,6 +85,9 @@ int main(int argc, char** argv, char** env)
// FIXME: It might be nice to tear down the emulator properly. // FIXME: It might be nice to tear down the emulator properly.
auto& emulator = *new UserspaceEmulator::Emulator(executable_path, arguments, environment); auto& emulator = *new UserspaceEmulator::Emulator(executable_path, arguments, environment);
emulator.set_profiling_details(dump_profile, profile_instruction_interval, profile_stream);
emulator.set_in_region_of_interest(!enable_roi_mode);
if (!emulator.load_elf()) if (!emulator.load_elf())
return 1; return 1;
@ -110,8 +109,8 @@ int main(int argc, char** argv, char** env)
rc = emulator.exec(); rc = emulator.exec();
if (g_dump_profile) { if (dump_profile)
g_profile_stream->write_or_error(R"(]})"sv.bytes()); emulator.profile_stream().write_or_error(R"(]})"sv.bytes());
}
return rc; return rc;
} }