Przeglądaj źródła

UserspaceEmulator: Move all the profiling details into the Emulator

Them being in the global namespace doesn't have a lot of fans, it seems.
Ali Mohammad Pur 4 lat temu
rodzic
commit
369e3da6a2

+ 7 - 12
Userland/DevTools/UserspaceEmulator/Emulator.cpp

@@ -27,11 +27,6 @@
 #    pragma GCC optimize("O3")
 #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 {
 
 static constexpr u32 stack_location = 0x10000000;
@@ -224,9 +219,9 @@ int Emulator::exec()
 
     constexpr bool trace = false;
 
-    size_t instructions_until_next_profile_dump = g_profile_instruction_interval;
-    if (g_dump_profile && 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));
+    size_t instructions_until_next_profile_dump = profile_instruction_interval();
+    if (is_profiling() && m_loader_text_size.has_value())
+        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) {
         if (m_steps_til_pause) [[likely]] {
@@ -239,10 +234,10 @@ int Emulator::exec()
 
             (m_cpu.*insn.handler())(insn);
 
-            if (g_dump_profile) {
+            if (is_profiling()) {
                 if (instructions_until_next_profile_dump == 0) {
-                    instructions_until_next_profile_dump = g_profile_instruction_interval;
-                    emit_profile_sample(*g_profile_stream);
+                    instructions_until_next_profile_dump = profile_instruction_interval();
+                    emit_profile_sample(profile_stream());
                 } else {
                     --instructions_until_next_profile_dump;
                 }
@@ -474,7 +469,7 @@ void Emulator::dump_backtrace()
 
 void Emulator::emit_profile_sample(AK::OutputStream& output)
 {
-    if (!g_in_region_of_interest)
+    if (!is_in_region_of_interest())
         return;
     StringBuilder builder;
     timeval tv {};

+ 23 - 0
Userland/DevTools/UserspaceEmulator/Emulator.h

@@ -12,6 +12,7 @@
 #include "Report.h"
 #include "SoftCPU.h"
 #include "SoftMMU.h"
+#include <AK/FileStream.h>
 #include <AK/MappedFile.h>
 #include <AK/Types.h>
 #include <LibDebug/DebugInfo.h>
@@ -32,6 +33,23 @@ public:
 
     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();
     void dump_backtrace();
     void dump_backtrace(Vector<FlatPtr> const&);
@@ -271,6 +289,11 @@ private:
     HashMap<String, CachedELF> m_dynamic_library_cache;
 
     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

+ 7 - 11
Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp

@@ -28,10 +28,6 @@
 #    pragma GCC optimize("O3")
 #endif
 
-extern bool g_dump_profile;
-extern Optional<OutputFileStream> g_profile_stream;
-extern bool g_in_region_of_interest;
-
 namespace UserspaceEmulator {
 
 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)
 {
-    if (g_dump_profile)
-        emit_profile_event(*g_profile_stream, "munmap", String::formatted("\"ptr\": {}, \"size\": {}", address, size));
+    if (is_profiling())
+        emit_profile_event(profile_stream(), "munmap", String::formatted("\"ptr\": {}, \"size\": {}", address, size));
     round_to_page_size(address, size);
     Vector<Region*, 4> marked_for_deletion;
     bool has_non_mmap_region = false;
@@ -877,8 +873,8 @@ u32 Emulator::virt$mmap(u32 params_addr)
         name_str = { name.data(), name.size() };
     }
 
-    if (g_dump_profile)
-        emit_profile_event(*g_profile_stream, "mmap", String::formatted(R"("ptr": {}, "size": {}, "name": "{}")", final_address, final_size, name_str));
+    if (is_profiling())
+        emit_profile_event(profile_stream(), "mmap", String::formatted(R"("ptr": {}, "size": {}, "name": "{}")", final_address, final_size, name_str));
 
     if (params.flags & MAP_ANONYMOUS) {
         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);
         return 0;
     case 5: // mark ROI start
-        if (g_in_region_of_interest)
+        if (is_in_region_of_interest())
             return -EINVAL;
-        g_in_region_of_interest = true;
+        m_is_in_region_of_interest = true;
         return 0;
     case 6: // mark ROI end
-        g_in_region_of_interest = false;
+        m_is_in_region_of_interest = false;
         return 0;
     default:
         return -EINVAL;

+ 18 - 19
Userland/DevTools/UserspaceEmulator/main.cpp

@@ -18,10 +18,6 @@
 #include <string.h>
 
 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)
 {
@@ -30,13 +26,15 @@ int main(int argc, char** argv, char** env)
     String profile_dump_path;
     FILE* profile_output_file { nullptr };
     bool enable_roi_mode { false };
+    bool dump_profile { false };
+    unsigned profile_instruction_interval { 0 };
 
     Core::ArgsParser parser;
     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(pause_on_startup, "Pause on startup", "pause", 'p');
-    parser.add_option(g_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(dump_profile, "Generate a ProfileViewer-compatible profile", "profile", 0);
+    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(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);
 
-    if (g_dump_profile && g_profile_instruction_interval == 0)
-        g_profile_instruction_interval = 128;
-
-    if (enable_roi_mode)
-        g_in_region_of_interest = false;
+    if (dump_profile && profile_instruction_interval == 0)
+        profile_instruction_interval = 128;
 
     String executable_path;
     if (arguments[0].contains("/"sv))
@@ -60,22 +55,23 @@ int main(int argc, char** argv, char** env)
         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());
 
-    if (g_dump_profile) {
+    OwnPtr<OutputFileStream> profile_stream;
+    if (dump_profile) {
         profile_output_file = fopen(profile_dump_path.characters(), "w+");
         if (profile_output_file == nullptr) {
             auto error_string = strerror(errno);
             warnln("Failed to open '{}' for writing: {}", profile_dump_path, error_string);
             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 {};
         gettimeofday(&tv, nullptr);
-        g_profile_stream->write_or_error(
+        profile_stream->write_or_error(
             String::formatted(
                 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)
@@ -89,6 +85,9 @@ int main(int argc, char** argv, char** env)
 
     // FIXME: It might be nice to tear down the emulator properly.
     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())
         return 1;
 
@@ -110,8 +109,8 @@ int main(int argc, char** argv, char** env)
 
     rc = emulator.exec();
 
-    if (g_dump_profile) {
-        g_profile_stream->write_or_error(R"(]})"sv.bytes());
-    }
+    if (dump_profile)
+        emulator.profile_stream().write_or_error(R"(]})"sv.bytes());
+
     return rc;
 }