From add3923cf49d7de005580016adb05ded9519c16f Mon Sep 17 00:00:00 2001 From: Christian von Elm Date: Thu, 7 Nov 2024 14:43:45 +0100 Subject: [PATCH] Make debuginfod configurable --- CMakeLists.txt | 30 ++- cmake/FindDebuginfod.cmake | 56 ++++ include/lo2s/dwarf_resolve.hpp | 8 +- include/lo2s/execution_scope.hpp | 2 +- include/lo2s/function_resolver.hpp | 31 ++- include/lo2s/instruction_resolver.hpp | 11 +- include/lo2s/measurement_scope.hpp | 5 + include/lo2s/perf/calling_context_manager.hpp | 13 +- include/lo2s/perf/event_reader.hpp | 4 - include/lo2s/perf/sample/writer.hpp | 2 +- include/lo2s/perf/types.hpp | 39 +-- include/lo2s/process_info.hpp | 58 ++-- include/lo2s/trace/reg_keys.hpp | 2 +- include/lo2s/trace/trace.hpp | 24 +- include/lo2s/util.hpp | 12 +- src/dwarf_resolve.cpp | 3 +- src/monitor/cpu_set_monitor.cpp | 6 +- src/monitor/main_monitor.cpp | 24 +- src/monitor/process_monitor.cpp | 15 +- src/monitor/system_process_monitor.cpp | 2 +- src/perf/sample/writer.cpp | 12 +- src/process_info.cpp | 247 ++++++++++-------- src/trace/trace.cpp | 156 ++++++----- src/util.cpp | 1 + 24 files changed, 443 insertions(+), 320 deletions(-) create mode 100644 cmake/FindDebuginfod.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 75254c1c..ee5439a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,9 @@ IfUpdatedUnsetAll(lo2s_USE_STATIC_LIBS Radare_USE_STATIC_LIBS Sensors_USE_STATIC_LIBS Veosinfo_USE_STATIC_LIBS - Audit_USE_STATIC_LIBS) + Audit_USE_STATIC_LIBS + Debuginfod_USE_STATIC_LIBS +) if(lo2s_USE_STATIC_LIBS STREQUAL "OFF") set(Dl_USE_STATIC_LIBS OFF CACHE BOOL "") @@ -56,7 +58,6 @@ if(lo2s_USE_STATIC_LIBS STREQUAL "OFF") else() if(lo2s_USE_STATIC_LIBS STREQUAL "MOSTLY") set(Dl_USE_STATIC_LIBS OFF CACHE BOOL "") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc") elseif(lo2s_USE_STATIC_LIBS STREQUAL "ALL") set(Dl_USE_STATIC_LIBS ON CACHE BOOL "") @@ -67,8 +68,6 @@ else() set(CMAKE_LINK_SEARCH_START_STATIC 1) set(CMAKE_LINK_SEARCH_END_STATIC 1) endif() - - if(lo2s_USE_STATIC_LIBS STREQUAL "MOSTLY") set(Dl_USE_STATIC_LIBS OFF CACHE BOOL "") set(LibElf_USE_STATIC_LIBS ON CACHE BOOL "") set(OTF2_USE_STATIC_LIBS ON CACHE BOOL "") @@ -81,6 +80,8 @@ else() set(Veosinfo_USE_STATIC_LIBS ON CACHE BOOL "") set(Radare_USE_STATIC_LIBS ON CACHE BOOL "") set(Audit_USE_STATIC_LIBS ON CACHE BOOL "") + set(Debuginfod_USE_STATIC_LIBS ON CACHE BOOL "") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc") endif() # Check if we are running Linux @@ -116,6 +117,7 @@ find_package(CUDAToolkit) find_package(Radare) find_package(Audit) find_package(LibElf REQUIRED) +find_package(Debuginfod) # configurable options @@ -135,6 +137,8 @@ CMAKE_DEPENDENT_OPTION(USE_VEOSINFO "Use libveosinfo to sample NEC SX-Aurora Tsu add_feature_info("USE_VEOSINFO" USE_VEOSINFO "Use libveosinfo to sample NEC SX-Aurora Tsubasa cards.") CMAKE_DEPENDENT_OPTION(USE_CUPTI "Use CUPTI to record CUDA activity." ON "CUDAToolkit_FOUND" OFF) add_feature_info("USE_CUPTI" USE_CUPTI "Use CUPTI to record CUDA activity.") +CMAKE_DEPENDENT_OPTION(USE_DEBUGINFOD "Use Debuginfod to download debug information on-demand." ON "Debuginfod_FOUND" OFF) +add_feature_info("USE_DEBUGINFOD" USE_DEBUGINFOD "Use Debuginfod to download debug information on-demand.") # system configuration checks CHECK_INCLUDE_FILES(linux/hw_breakpoint.h HAVE_HW_BREAKPOINT_H) CHECK_STRUCT_HAS_MEMBER("struct perf_event_attr" clockid linux/perf_event.h HAVE_PERF_EVENT_ATTR_CLOCKID) @@ -231,17 +235,8 @@ target_link_libraries(lo2s std::filesystem LibElf::LibElf LibElf::LibDw - debuginfod ) -find_path(DEBUGINFOD_INCLUDE_DIRS elfutils/debuginfod.h - PATHS ENV C_INCLUDE_PATH ENV CPATH - PATH_SUFFIXES include) - -if(DEBUGINFOD_INCLUDE_DIRS) - target_compile_definitions(lo2s PUBLIC HAVE_DEBUGINFOD) -endif() - # old glibc versions require -lrt for clock_gettime() if(NOT CLOCK_GETTIME_FOUND) if(CLOCK_GETTIME_FOUND_WITH_RT) @@ -321,6 +316,15 @@ if (USE_VEOSINFO) endif() endif() +if (USE_DEBUGINFOD) + if (Debuginfod_FOUND) + target_compile_definitions(lo2s PUBLIC HAVE_DEBUGINFOD) + target_link_libraries(lo2s PRIVATE Debuginfod::Debuginfod) + else() + message(SEND_ERROR "Debuginfod not found but requested") + endif() +endif() + if (USE_LIBPFM) if (Libpfm_FOUND) target_compile_definitions(lo2s PUBLIC HAVE_LIBPFM) diff --git a/cmake/FindDebuginfod.cmake b/cmake/FindDebuginfod.cmake new file mode 100644 index 00000000..cb39e068 --- /dev/null +++ b/cmake/FindDebuginfod.cmake @@ -0,0 +1,56 @@ +# Copyright (c) 2022, Technische Universität Dresden, Germany +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted +# provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions +# and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions +# and the following disclaimer in the documentation and/or other materials provided with the +# distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse +# or promote products derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include(${CMAKE_CURRENT_LIST_DIR}/UnsetIfUpdated.cmake) + +# Linking libelf isn't a great default because it produces warnings +option(Debuginfod_USE_STATIC_LIBS "Link debuginfod statically." OFF) + +UnsetIfUpdated(Debuginfod_LIBRARY Debuginfod_USE_STATIC_LIBS) + +find_path(Debuginfod_INCLUDE_DIRS libelf.h + PATHS ENV C_INCLUDE_PATH ENV CPATH + PATH_SUFFIXES include) + +if(Debuginfod_USE_STATIC_LIBS) + find_library(Debuginfod_LIBRARY NAMES libdebuginfod.a + HINTS ENV LIBRARY_PATH) +else() + find_library(Debuginfod_LIBRARY NAMES libdebuginfod.so + HINTS ENV LIBRARY_PATH LD_LIBRARY_PATH) +endif() + +include (FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Debuginfod DEFAULT_MSG + Debuginfod_LIBRARY + Debuginfod_INCLUDE_DIRS) + +if(Debuginfod_FOUND) + add_library(Debuginfod::Debuginfod UNKNOWN IMPORTED) + set_property(TARGET Debuginfod::Debuginfod PROPERTY IMPORTED_LOCATION ${Debuginfod_LIBRARY}) + target_include_directories(Debuginfod::Debuginfod INTERFACE ${Debuginfod_INCLUDE_DIRS}) +endif() + +mark_as_advanced(Debuginfod_LIBRARY Debuginfod_INCLUDE_DIRS) diff --git a/include/lo2s/dwarf_resolve.hpp b/include/lo2s/dwarf_resolve.hpp index cc56bdba..43f9ec69 100644 --- a/include/lo2s/dwarf_resolve.hpp +++ b/include/lo2s/dwarf_resolve.hpp @@ -20,11 +20,15 @@ class DwarfFunctionResolver : public FunctionResolver public: DwarfFunctionResolver(std::string name); - static FunctionResolver& cache(std::string name) + static std::shared_ptr cache(std::string name) { - return StringCache::instance()[name]; + return BinaryCache::instance()[name]; } + DwarfFunctionResolver(DwarfFunctionResolver&) = delete; + DwarfFunctionResolver& operator=(DwarfFunctionResolver&) = delete; + DwarfFunctionResolver(DwarfFunctionResolver&&) = delete; + DwarfFunctionResolver& operator=(DwarfFunctionResolver&&) = delete; ~DwarfFunctionResolver(); virtual LineInfo lookup_line_info(Address addr) override; diff --git a/include/lo2s/execution_scope.hpp b/include/lo2s/execution_scope.hpp index b68925c8..aa1f1403 100644 --- a/include/lo2s/execution_scope.hpp +++ b/include/lo2s/execution_scope.hpp @@ -72,7 +72,7 @@ class ExecutionScope case ExecutionScopeType::THREAD: return fmt::format("thread {}", id); case ExecutionScopeType::PROCESS: - return fmt::format("process {}"); + return fmt::format("process {}", id); case ExecutionScopeType::CPU: return fmt::format("cpu {}", id); default: diff --git a/include/lo2s/function_resolver.hpp b/include/lo2s/function_resolver.hpp index bd05256d..00b90440 100644 --- a/include/lo2s/function_resolver.hpp +++ b/include/lo2s/function_resolver.hpp @@ -24,8 +24,8 @@ #include #include -#include #include +#include namespace lo2s { @@ -36,9 +36,9 @@ class FunctionResolver { } - static FunctionResolver& cache(const std::string& name) + static std::shared_ptr cache(const std::string& name) { - return StringCache::instance()[name]; + return BinaryCache::instance()[name]; } virtual LineInfo lookup_line_info(Address) @@ -51,6 +51,15 @@ class FunctionResolver return name_; } + virtual void insert(std::map& functions [[maybe_unused]]) + { + throw std::runtime_error("Class does not support inserting elements"); + } + + virtual ~FunctionResolver() + { + } + protected: std::string name_; }; @@ -61,8 +70,14 @@ class Kallsyms : public FunctionResolver Kallsyms() : FunctionResolver("[kernel]") { std::map entries; - std::ifstream ksyms_file("/proc/kallsyms"); + std::ifstream ksyms_file; + ksyms_file.exceptions(std::ifstream::badbit); + ksyms_file.open("/proc/kallsyms"); + if (!ksyms_file.good()) + { + return; + } std::regex ksym_regex("([0-9a-f]+) (?:t|T) ([^[:space:]]+)"); std::smatch ksym_match; @@ -107,9 +122,9 @@ class Kallsyms : public FunctionResolver } } - static Kallsyms& cache() + static std::shared_ptr cache() { - static Kallsyms k; + static std::shared_ptr k = std::make_shared(); return k; } @@ -125,6 +140,6 @@ class Kallsyms : public FunctionResolver private: std::map kallsyms_; - uint64_t start_; + uint64_t start_ = UINT64_MAX; }; -} +} // namespace lo2s diff --git a/include/lo2s/instruction_resolver.hpp b/include/lo2s/instruction_resolver.hpp index c1d32971..bb3b80bd 100644 --- a/include/lo2s/instruction_resolver.hpp +++ b/include/lo2s/instruction_resolver.hpp @@ -19,7 +19,7 @@ * along with lo2s. If not, see . */ -#pragma once +#pragma once #include #ifdef HAVE_RADARE @@ -28,6 +28,7 @@ #include #include + namespace lo2s { class InstructionResolver @@ -47,6 +48,10 @@ class InstructionResolver { return ""; } + + virtual ~InstructionResolver() + { + } }; #ifdef HAVE_RADARE class RadareInstructionResolver : public InstructionResolver @@ -56,9 +61,9 @@ class RadareInstructionResolver : public InstructionResolver { } - static RadareInstructionResolver& cache(const std::string& name) + static std::shared_ptr cache(const std::string& name) { - return StringCache::instance()[name]; + return BinaryCache::instance()[name]; } virtual std::string lookup_instruction(Address ip) diff --git a/include/lo2s/measurement_scope.hpp b/include/lo2s/measurement_scope.hpp index 8e9378fa..7656d98e 100644 --- a/include/lo2s/measurement_scope.hpp +++ b/include/lo2s/measurement_scope.hpp @@ -96,6 +96,11 @@ struct MeasurementScope return (lhs.scope == rhs.scope) && lhs.type == rhs.type; } + MeasurementScope from_ex_scope(ExecutionScope new_scope) + { + return MeasurementScope(type, new_scope); + } + friend bool operator<(const MeasurementScope& lhs, const MeasurementScope& rhs) { if (lhs.type != rhs.type) diff --git a/include/lo2s/perf/calling_context_manager.hpp b/include/lo2s/perf/calling_context_manager.hpp index 268a0469..9ee7db8a 100644 --- a/include/lo2s/perf/calling_context_manager.hpp +++ b/include/lo2s/perf/calling_context_manager.hpp @@ -22,7 +22,7 @@ #include #include - +#include #include extern "C" @@ -46,7 +46,7 @@ struct LocalCctx class LocalCctxMap { public: - LocalCctxMap() + LocalCctxMap(MeasurementScope scope) : scope_(scope) { } @@ -79,7 +79,7 @@ class LocalCctxMap // information. // // Having these things in mind, look at this line and tell me, why it is still wrong: - auto children = &map[p]; + auto children = &map[scope_.from_ex_scope(p.as_scope())]; uint64_t ref = -1; for (uint64_t i = num_ips - 1;; i--) { @@ -112,7 +112,7 @@ class LocalCctxMap otf2::definition::calling_context::reference_type sample_ref(Process p, uint64_t ip) { - auto it = find_ip_child(ip, map[p]); + auto it = find_ip_child(ip, map[scope_.from_ex_scope(p.as_scope())]); return it->second.ref; } @@ -140,7 +140,7 @@ class LocalCctxMap return thread_cctxs_; } - const std::map>& get_functions() const + const std::map>& get_functions() const { return map; } @@ -170,8 +170,9 @@ class LocalCctxMap } private: - std::map> map; + std::map> map; std::map> thread_cctxs_; + MeasurementScope scope_; /* * Stores calling context information for each sample writer / monitoring thread. diff --git a/include/lo2s/perf/event_reader.hpp b/include/lo2s/perf/event_reader.hpp index 587e8726..8d561e91 100644 --- a/include/lo2s/perf/event_reader.hpp +++ b/include/lo2s/perf/event_reader.hpp @@ -66,7 +66,6 @@ class EventReader using RecordUnknownType = perf_event_header; using RecordMmapType = lo2s::RecordMmapType; - using RecordMmap2Type = lo2s::RecordMmap2Type; using RecordCommType = lo2s::RecordCommType; struct RecordLostType @@ -176,9 +175,6 @@ class EventReader case PERF_RECORD_MMAP: stop = crtp_this->handle((const RecordMmapType*)event_header_p); break; - case PERF_RECORD_MMAP2: - stop = crtp_this->handle((const RecordMmap2Type*)event_header_p); - break; case PERF_RECORD_SWITCH: stop = crtp_this->handle((const RecordSwitchType*)event_header_p); break; diff --git a/include/lo2s/perf/sample/writer.hpp b/include/lo2s/perf/sample/writer.hpp index b589dbac..59759d08 100644 --- a/include/lo2s/perf/sample/writer.hpp +++ b/include/lo2s/perf/sample/writer.hpp @@ -63,7 +63,7 @@ class Writer : public Reader public: using Reader::handle; bool handle(const Reader::RecordSampleType* sample); - bool handle(const Reader::RecordMmap2Type* mmap_event); + bool handle(const Reader::RecordMmapType* mmap_event); bool handle(const Reader::RecordCommType* comm); bool handle(const Reader::RecordSwitchCpuWideType* context_switch); bool handle(const Reader::RecordSwitchType* context_switch); diff --git a/include/lo2s/perf/types.hpp b/include/lo2s/perf/types.hpp index 64468c99..4dd9b294 100644 --- a/include/lo2s/perf/types.hpp +++ b/include/lo2s/perf/types.hpp @@ -43,6 +43,17 @@ class PerfEventCache PerfEventCache(const PerfEventCache&) = delete; PerfEventCache& operator=(const PerfEventCache&) = delete; + PerfEventCache(PerfEventCache&& other) + { + std::swap(data_, other.data_); + } + + PerfEventCache& operator=(PerfEventCache&& other) + { + std::swap(data_, other.data_); + return *this; + } + PerfEventCache(const T* event) : data_(std::make_unique(event->header.size)) { memcpy(data_.get(), event, event->header.size); @@ -101,33 +112,7 @@ struct RecordCommType // struct sample_id id; }; -struct RecordMmap2Type -{ - // BAD things happen if you try this - RecordMmap2Type() = delete; - RecordMmap2Type(const RecordMmap2Type&) = delete; - RecordMmap2Type& operator=(const RecordMmap2Type&) = delete; - RecordMmap2Type(RecordMmap2Type&&) = delete; - RecordMmap2Type& operator=(RecordMmap2Type&&) = delete; - - struct perf_event_header header; - uint32_t pid; - uint32_t tid; - uint64_t addr; - uint64_t len; - uint64_t pgoff; - uint32_t maj; - uint32_t min; - uint64_t ino; - uint64_t ino_generation; - uint32_t prot; - uint32_t flags; - // Note ISO C++ forbids zero-size array, but this struct is exclusively used as pointer - char filename[1]; - // struct sample_id sample_id; -}; - -using RawMemoryMapCache = std::deque>; +using RawMemoryMapCache = std::deque>; using RawCommCache = std::deque>; } // namespace lo2s diff --git a/include/lo2s/process_info.hpp b/include/lo2s/process_info.hpp index 53d586f0..7c7bdf74 100644 --- a/include/lo2s/process_info.hpp +++ b/include/lo2s/process_info.hpp @@ -22,10 +22,11 @@ #pragma once #include +#include #include #include -#include #include +#include #include #include @@ -48,33 +49,60 @@ class ProcessInfo return process_; } - void mmap(const RecordMmap2Type& entry) + void mmap(const RecordMmapType& entry) { mmap(entry.addr, entry.addr + entry.len, entry.pgoff, entry.filename); } void mmap(Address addr, Address end, Address pgoff, std::string filename); - LineInfo lookup_line_info(Address ip); - std::string lookup_instruction(Address ip) const; + LineInfo lookup_line_info(MeasurementScope scope, Address ip); + std::string lookup_instruction(MeasurementScope scope, Address ip) const; private: + void emplace_fr(Address addr, Address end, Address pgoff, std::string filename); + void emplace_ir(Address addr, Address end, Address pgoff, std::string filename); + struct Mapping { - Mapping(Address s, Address e, Address o, FunctionResolver& f, InstructionResolver& i) - : start(s), end(e), pgoff(o), fr(f), ir(i) + Mapping(Address s, Address e, Address o) : range(s, e), pgoff(o) + { + } + + Mapping(Address s) : range(s), pgoff(0) { } - Address start; - Address end; + Range range; Address pgoff; - FunctionResolver& fr; - InstructionResolver& ir; + + bool operator==(const Address& other) const + { + return other >= range.start && other < range.end; + } + + bool operator<(const Mapping& other) const + { + return range < other.range; + } + + bool operator<(const Address& other) const + { + return range < other; + } + + static Mapping max() + { + return Mapping(0, (uint64_t)-1, 0); + } }; + const Process process_; mutable std::shared_mutex mutex_; - std::map map_; + std::map>> + function_resolvers_; + std::map>> + instruction_resolvers_; }; class ProcessMap @@ -84,13 +112,13 @@ class ProcessMap { } - bool has(Process p, uint64_t timepoint); + bool has(Process p); - ProcessInfo& get(Process p, uint64_t timepoint); + ProcessInfo& get(Process p); - ProcessInfo& insert(Process p, uint64_t timepoint, bool read_initial); + ProcessInfo& insert(Process p, bool read_initial); private: - std::map> infos_; + std::map infos_; }; } // namespace lo2s diff --git a/include/lo2s/trace/reg_keys.hpp b/include/lo2s/trace/reg_keys.hpp index c4484c89..31b55c6a 100644 --- a/include/lo2s/trace/reg_keys.hpp +++ b/include/lo2s/trace/reg_keys.hpp @@ -235,7 +235,7 @@ template <> struct Holder { using type = otf2::lookup_definition_holder; + ByProcess, ByLineInfo, BySyscall>; }; template <> diff --git a/include/lo2s/trace/trace.hpp b/include/lo2s/trace/trace.hpp index 0aee5727..9336bb2d 100644 --- a/include/lo2s/trace/trace.hpp +++ b/include/lo2s/trace/trace.hpp @@ -70,17 +70,14 @@ class Trace otf2::chrono::time_point record_from() const; otf2::chrono::time_point record_to() const; - void add_process(Process parent, Process process, const std::string& name = ""); + void emplace_process(Process parent, Process process, const std::string& name = ""); - void add_thread(Thread t, const std::string& name); - void add_threads(const std::unordered_map& thread_map); + void emplace_thread(Thread t, const std::string& name = ""); + void emplace_threads(const std::unordered_map& thread_map); void add_monitoring_thread(Thread t, const std::string& name, const std::string& group); - void update_process_name(Process p, const std::string& name); - void update_thread_name(Thread t, const std::string& name); - - LocalCctxMap& create_local_cctx_map(); + LocalCctxMap& create_local_cctx_map(MeasurementScope scope); otf2::definition::mapping_table merge_calling_contexts(const LocalCctxMap& local_cctxs, ProcessMap& infos); void merge_calling_contexts(ProcessMap& process_infos); @@ -296,12 +293,13 @@ class Trace * This is a helper needed to avoid constant re-locking when adding * multiple threads via #add_threads. **/ - void add_thread_exclusive(Thread thread, const std::string& name, - const std::lock_guard&); + void emplace_thread_exclusive(Thread thread, const std::string& name, + const std::lock_guard&); void merge_ips(const std::map& new_children, std::map& children, std::vector& mapping_table, - otf2::definition::calling_context& parent, ProcessMap& infos, Process p); + otf2::definition::calling_context& parent, ProcessInfo& info, + MeasurementScope scope); const otf2::definition::system_tree_node bio_parent_node(BlockDevice& device) { @@ -317,14 +315,14 @@ class Trace return bio_system_tree_node_; } + void update_thread(Thread t, const std::string& name); + void update_process(Process parent, Process process, const std::string& name); const otf2::definition::string& intern_syscall_str(int64_t syscall_nr); const otf2::definition::source_code_location& intern_scl(const LineInfo&); const otf2::definition::region& intern_region(const LineInfo&); - const otf2::definition::system_tree_node& intern_process_node(Process process); - const otf2::definition::string& intern(const std::string&); void add_lo2s_property(const std::string& name, const std::string& value); @@ -351,7 +349,7 @@ class Trace std::map thread_names_; std::map global_thread_cctxs_; - std::map> calling_context_tree_; + std::map> calling_context_tree_; otf2::definition::comm_locations_group& comm_locations_group_; otf2::definition::comm_locations_group& hardware_comm_locations_group_; diff --git a/include/lo2s/util.hpp b/include/lo2s/util.hpp index efd3fca3..3f1255b6 100644 --- a/include/lo2s/util.hpp +++ b/include/lo2s/util.hpp @@ -61,23 +61,23 @@ struct MallocDelete } // namespace memory template -class StringCache +class BinaryCache { public: - static StringCache& instance() + static BinaryCache& instance() { - static StringCache l; + static BinaryCache l; return l; } - T& operator[](const std::string& name) + std::shared_ptr operator[](const std::string& name) { std::lock_guard guard(mutex_); - return elements_.try_emplace(name, name).first->second; + return elements_.try_emplace(name, std::make_shared(name)).first->second; } private: - std::unordered_map elements_; + std::unordered_map> elements_; std::mutex mutex_; }; diff --git a/src/dwarf_resolve.cpp b/src/dwarf_resolve.cpp index 5b922afd..94fa7b4c 100644 --- a/src/dwarf_resolve.cpp +++ b/src/dwarf_resolve.cpp @@ -77,8 +77,7 @@ DwarfFunctionResolver::DwarfFunctionResolver(std::string name) : FunctionResolve mod_ = dwfl_report_offline(dwfl_, name.c_str(), name.c_str(), -1); if (mod_ == nullptr) { - const char* errmsg = dwfl_errmsg(dwfl_errno()); - Log::error() << "Could not add " << name << " " << errmsg; + throw std::runtime_error(dwfl_errmsg(dwfl_errno())); } dwfl_report_end(dwfl_, NULL, NULL); } diff --git a/src/monitor/cpu_set_monitor.cpp b/src/monitor/cpu_set_monitor.cpp index 306c295c..f9235e95 100644 --- a/src/monitor/cpu_set_monitor.cpp +++ b/src/monitor/cpu_set_monitor.cpp @@ -57,12 +57,12 @@ CpuSetMonitor::CpuSetMonitor() : MainMonitor() { pid = std::stol(pid_match[1]); - process_infos_.insert(Process(pid), 0, true); + process_infos_.insert(Process(pid), true); } } } - trace_.add_threads(get_comms_for_running_threads()); + trace_.emplace_threads(get_comms_for_running_threads()); try { @@ -137,7 +137,7 @@ void CpuSetMonitor::run() } } - trace_.add_threads(get_comms_for_running_threads()); + trace_.emplace_threads(get_comms_for_running_threads()); for (auto& monitor_elem : monitors_) { diff --git a/src/monitor/main_monitor.cpp b/src/monitor/main_monitor.cpp index 339eaa17..311c3885 100644 --- a/src/monitor/main_monitor.cpp +++ b/src/monitor/main_monitor.cpp @@ -129,38 +129,22 @@ MainMonitor::MainMonitor() : trace_(), metrics_(trace_) #endif } -static uint64_t mmap_get_time(const RecordMmap2Type* t) -{ - struct sample_id* id = - (struct sample_id*)((char*)t + t->header.size - sizeof(struct sample_id)); - return id->time; -} - -static uint64_t comm_get_time(const RecordCommType* t) -{ - struct sample_id* id = - (struct sample_id*)((char*)t + t->header.size - sizeof(struct sample_id)); - return id->time; -} - void MainMonitor::insert_cached_events(const RawMemoryMapCache& cached_mmaps, const RawCommCache& cached_execs) { for (auto& event : cached_execs) { - process_infos_.insert(Process(event.get()->pid), comm_get_time(event.get()), false); + process_infos_.insert(Process(event.get()->pid), false); } for (auto& event : cached_mmaps) { - const uint64_t timestamp = mmap_get_time(event.get()); Process p = Process(event.get()->pid); - if (!process_infos_.has(p, timestamp)) + if (!process_infos_.has(p)) { - process_infos_.insert(p, timestamp, false); + process_infos_.insert(p, false); } - - ProcessInfo& pinfo = process_infos_.get(p, timestamp); + ProcessInfo& pinfo = process_infos_.get(p); pinfo.mmap(*event.get()); } diff --git a/src/monitor/process_monitor.cpp b/src/monitor/process_monitor.cpp index 4ccbd752..e094d94e 100644 --- a/src/monitor/process_monitor.cpp +++ b/src/monitor/process_monitor.cpp @@ -36,18 +36,21 @@ ProcessMonitor::ProcessMonitor() : MainMonitor() void ProcessMonitor::insert_process(Process parent, Process process, std::string proc_name, bool spawn) { - trace_.add_process(parent, process, proc_name); - insert_thread(process, process.as_thread(), proc_name, spawn, true); + trace_.emplace_process(parent, process, proc_name); + insert_thread(process, process.as_thread(), proc_name, spawn); } void ProcessMonitor::insert_thread(Process process, Thread thread, std::string name, bool spawn, bool is_process) { - trace_.add_thread(thread, name); + trace_.emplace_thread(thread, name); if (config().sampling) { - process_infos_.insert(process, 0, !spawn); + if (!process_infos_.has(process)) + { + process_infos_.insert(process, !spawn); + } } ExecutionScope scope = ExecutionScope(thread); @@ -74,12 +77,12 @@ void ProcessMonitor::insert_thread(Process process, Thread thread, std::string n } } - trace_.update_thread_name(thread, name); + trace_.emplace_thread(thread, name); } void ProcessMonitor::update_process_name(Process process, const std::string& name) { - trace_.update_process_name(process, name); + trace_.emplace_process(trace::Trace::NO_PARENT_PROCESS, process, name); } void ProcessMonitor::exit_thread(Thread thread) diff --git a/src/monitor/system_process_monitor.cpp b/src/monitor/system_process_monitor.cpp index a86d07d6..e822dc1d 100644 --- a/src/monitor/system_process_monitor.cpp +++ b/src/monitor/system_process_monitor.cpp @@ -39,7 +39,7 @@ void SystemProcessMonitor::insert_thread([[maybe_unused]] Process process, Threa { // in system monitoring, we only need to track the threads spawned from the process lo2s spawned // itself. Without this, these threads end up as "". Sad times. - trace_.add_thread(thread, name); + trace_.emplace_thread(thread, name); } void SystemProcessMonitor::update_process_name([[maybe_unused]] Process process, diff --git a/src/perf/sample/writer.cpp b/src/perf/sample/writer.cpp index 924384fe..b961269c 100644 --- a/src/perf/sample/writer.cpp +++ b/src/perf/sample/writer.cpp @@ -39,6 +39,7 @@ #include #include +#include extern "C" { @@ -59,7 +60,7 @@ Writer::Writer(ExecutionScope scope, monitor::MainMonitor& Monitor, trace::Trace cpuid_metric_instance_(trace.metric_instance(trace.cpuid_metric_class(), otf2_writer_.location(), otf2_writer_.location())), cpuid_metric_event_(otf2::chrono::genesis(), cpuid_metric_instance_), - local_cctx_map_(trace.create_local_cctx_map()), + local_cctx_map_(trace.create_local_cctx_map(MeasurementScope::sample(scope))), time_converter_(perf::time::Converter::instance()), first_time_point_(lo2s::time::now()), last_time_point_(first_time_point_) { @@ -98,7 +99,7 @@ bool Writer::handle(const Reader::RecordSampleType* sample) return false; } -bool Writer::handle(const Reader::RecordMmap2Type* mmap_event) +bool Writer::handle(const Reader::RecordMmapType* mmap_event) { // Since this is an mmap record (as opposed to mmap2), it will only be generated for executable if (!scope_.is_cpu() && scope_ != ExecutionScope(Thread(mmap_event->tid))) @@ -211,12 +212,13 @@ bool Writer::handle(const Reader::RecordCommType* comm) << " changed name to \"" << new_command << "\""; // update task name - trace_.update_thread_name(Thread(comm->tid), new_command); + trace_.emplace_thread(Thread(comm->tid), new_command); // only update name of process if the main thread changes its name if (comm->pid == comm->tid) { - trace_.update_process_name(Process(comm->pid), new_command); + trace_.emplace_process(trace::Trace::NO_PARENT_PROCESS, Process(comm->pid), + new_command); } } @@ -257,7 +259,7 @@ void Writer::end() trace_.process_comm(scope_.as_thread()), -1); } - trace_.add_threads(comms_); + trace_.emplace_threads(comms_); monitor_.insert_cached_events(cached_mmap_events_, cached_comm_events_); } diff --git a/src/process_info.cpp b/src/process_info.cpp index 400bfb50..e6fe839c 100644 --- a/src/process_info.cpp +++ b/src/process_info.cpp @@ -26,11 +26,24 @@ namespace lo2s ProcessInfo::ProcessInfo(Process p, bool read_initial) : process_(p) { - FunctionResolver& kall = Kallsyms::cache(); - InstructionResolver& kernel_ir = InstructionResolver::cache(); - map_.emplace( - std::piecewise_construct, std::forward_as_tuple(Kallsyms::cache().start(), (uint64_t)-1), - std::forward_as_tuple(Kallsyms::cache().start(), (uint64_t)-1, 0, kall, kernel_ir)); + try + { + + std::shared_ptr kall = Kallsyms::cache(); + + auto& fr_map = function_resolvers_ + .emplace(MeasurementScope::sample(p.as_scope()), + std::map>()) + .first->second; + + fr_map.emplace(std::piecewise_construct, + std::forward_as_tuple(Kallsyms::cache()->start(), (uint64_t)-1, 0), + std::forward_as_tuple(kall)); + } + catch (std::exception& e) + { + Log::debug() << "Could not read kallsyms: " << e.what(); + } if (!read_initial) { return; @@ -65,84 +78,57 @@ ProcessInfo::ProcessInfo(Process p, bool read_initial) : process_(p) } } -void ProcessInfo::mmap(Address addr, Address end, Address pgoff, std::string filename) +void ProcessInfo::emplace_fr(Address addr, Address end, Address pgoff, std::string filename) { - - std::lock_guard lock(mutex_); - - Log::debug() << "mmap: " << addr << "-" << end << " " << pgoff << ": " << filename; - - if (filename.empty() || std::string("//anon") == filename || - std::string("/dev/zero") == filename || std::string("/anon_hugepage") == filename || - nitro::lang::starts_with(filename, "/memfd") || - nitro::lang::starts_with(filename, "/SYSV") || nitro::lang::starts_with(filename, "/dev")) - { - Log::debug() << "mmap: skipping fr: " << filename << " (known non-library)"; - return; - } - - FunctionResolver* fr; - InstructionResolver* ir; - + std::shared_ptr fr; try { if (nitro::lang::starts_with(filename, "[")) { - fr = &FunctionResolver::cache(filename); + fr = FunctionResolver::cache(filename); } else { - fr = &DwarfFunctionResolver::cache(filename); + fr = DwarfFunctionResolver::cache(filename); } } - catch (...) + catch (std::exception& e) { - fr = &FunctionResolver::cache(filename); + fr = FunctionResolver::cache(filename); } -#ifdef HAVE_RADARE - try + if (fr == nullptr) { - ir = &RadareInstructionResolver::cache(filename); - } - catch (...) - { - ir = &InstructionResolver::cache(); + return; } -#else - ir = &InstructionResolver::cache(); -#endif - auto ex_it = map_.find(addr); - if (ex_it != map_.end()) + auto& fr_map = function_resolvers_ + .emplace(MeasurementScope::sample(process_.as_scope()), + std::map>()) + .first->second; + + auto fr_entry = fr_map.find(Mapping(addr)); + if (fr_entry != fr_map.end()) { // Overlapping with existing entry - auto ex_range = ex_it->first; - auto ex_elem = std::move(ex_it->second); - map_.erase(ex_it); - if (ex_range.start != addr) + auto fr_mapping = fr_entry->first; + auto fr = std::move(fr_entry->second); + fr_map.erase(fr_entry); + if (fr_mapping.range.start != addr) { // Truncate entry - assert(ex_range.start < addr); - ex_range.end = addr; - Log::debug() << "truncating map entry at " << ex_range.start << " to " << ex_range.end; - [[maybe_unused]] auto r = map_.emplace(ex_range, std::move(ex_elem)); + assert(fr_mapping.range.start < addr); + fr_mapping.range.end = addr; + Log::debug() << "truncating map entry at " << fr_mapping.range.start << " to " + << fr_mapping.range.end; + [[maybe_unused]] auto r = fr_map.emplace(fr_mapping, std::move(fr)); assert(r.second); } } try { - auto r = map_.emplace(std::piecewise_construct, std::forward_as_tuple(addr, end), - std::forward_as_tuple(addr, end, pgoff, *fr, *ir)); - if (!r.second) - { - // very common, so only debug - // TODO handle better - Log::debug() << "duplicate memory range from mmap event. new: " << addr << "-" << end - << "%" << pgoff << " " << filename << "\n" - << "OLD: " << r.first->second.start << "-" << r.first->second.end << "%" - << r.first->second.pgoff << " " << r.first->second.fr.name(); - } + fr_map.emplace(std::piecewise_construct, std::forward_as_tuple(addr, end, pgoff), + std::forward_as_tuple(fr)); } catch (Range::Error& e) { @@ -152,80 +138,133 @@ void ProcessInfo::mmap(Address addr, Address end, Address pgoff, std::string fil } } -LineInfo ProcessInfo::lookup_line_info(Address ip) +void ProcessInfo::emplace_ir(Address addr, Address end, Address pgoff, std::string filename) { + std::shared_ptr ir = nullptr; +#ifdef HAVE_RADARE try { - std::shared_lock lock(mutex_); - return map_.at(ip).fr.lookup_line_info(ip - map_.at(ip).start + map_.at(ip).pgoff); + ir = RadareInstructionResolver::cache(filename); } - catch (std::exception& e) + catch (...) { - Log::error() << process_ << ": Could not find mapping for ip: " << ip << e.what(); - return LineInfo::for_unknown_function(); } -} - -std::string ProcessInfo::lookup_instruction(Address ip) const -{ - return map_.at(ip).ir.lookup_instruction(ip - map_.at(ip).start + map_.at(ip).pgoff); -} +#endif -bool ProcessMap::has(Process p, uint64_t timepoint) -{ - auto it = infos_.find(p); - if (it == infos_.end()) + if (ir == nullptr) { - return false; + return; } - for (auto& elem : it->second) + + auto& ir_map = instruction_resolvers_ + .emplace(MeasurementScope::sample(process_.as_scope()), + std::map>()) + .first->second; + + auto ir_entry = ir_map.find(Mapping(addr)); + if (ir_entry != ir_map.end()) { - if (timepoint >= elem.first) + // Overlapping with existing entry + auto ir_mapping = ir_entry->first; + auto ir = std::move(ir_entry->second); + ir_map.erase(ir_entry); + if (ir_mapping.range.start != addr) { - return true; + // Truncate entry + assert(ir_mapping.range.start < addr); + ir_mapping.range.end = addr; + Log::debug() << "truncating map entry at " << ir_mapping.range.start << " to " + << ir_mapping.range.end; + [[maybe_unused]] auto r = ir_map.emplace(ir_mapping, std::move(ir)); + assert(r.second); } } - return false; + + try + { + ir_map.emplace(std::piecewise_construct, std::forward_as_tuple(addr, end, pgoff), + std::forward_as_tuple(ir)); + } + catch (Range::Error& e) + { + // Very common, can't warn here + // TODO consider handling this somehow... + Log::debug() << "invalid address range in /proc/.../maps: " << e.what(); + } } -ProcessInfo& ProcessMap::get(Process p, uint64_t timepoint) +void ProcessInfo::mmap(Address addr, Address end, Address pgoff, std::string filename) { - auto& infos = infos_.at(p); - auto it = std::find_if(infos.begin(), infos.end(), - [&timepoint](auto& arg) { return arg.first > timepoint; }); + std::lock_guard lock(mutex_); + + Log::debug() << "mmap: " << addr << "-" << end << " " << pgoff << ": " << filename; - if (it == infos.begin()) + if (filename.empty() || std::string("//anon") == filename || + std::string("/dev/zero") == filename || std::string("/anon_hugepage") == filename || + nitro::lang::starts_with(filename, "/memfd") || + nitro::lang::starts_with(filename, "/SYSV") || nitro::lang::starts_with(filename, "/dev")) { - if (timepoint >= it->first) - { - return it->second; - } - else - { - throw std::out_of_range("no matching timepoint"); - } + Log::debug() << "mmap: skipping fr: " << filename << " (known non-library)"; + return; } - else + + emplace_fr(addr, end, pgoff, filename); + emplace_ir(addr, end, pgoff, filename); +} + +LineInfo ProcessInfo::lookup_line_info(MeasurementScope scope, Address ip) +{ + try { - it--; - if (timepoint >= it->first) - { - return it->second; - } - else + std::shared_lock lock(mutex_); + + auto& fr_map = function_resolvers_.at(scope); + for (auto& fr : fr_map) { - throw std::out_of_range("no matching timepoint it--"); + if (ip >= fr.first.range.start && ip < fr.first.range.end) + { + return fr.second->lookup_line_info(ip - fr.first.range.start + fr.first.pgoff); + } } } + catch (std::exception& e) + { + Log::debug() << process_ << ": Could not find mapping for ip: " << ip << e.what(); + } + return LineInfo::for_unknown_function(); +} + +std::string ProcessInfo::lookup_instruction(MeasurementScope scope, Address ip) const +{ + auto& ir_map = instruction_resolvers_.at(scope); - return infos_.at(p).at(timepoint); + auto ir = ir_map.find(Mapping(ip)); + if (ir != ir_map.end()) + { + return ir->second->lookup_instruction(ip - ir->first.range.start + ir->first.pgoff); + } + return ""; } -ProcessInfo& ProcessMap::insert(Process p, uint64_t timepoint, bool read_initial) +bool ProcessMap::has(Process p) { - auto it = infos_[p].emplace(std::piecewise_construct, std::forward_as_tuple(timepoint), - std::forward_as_tuple(p, read_initial)); + return infos_.count(p) != 0; +} + +ProcessInfo& ProcessMap::get(Process p) +{ + return infos_.at(p); +} + +ProcessInfo& ProcessMap::insert(Process p, bool read_initial) +{ + if (infos_.count(p)) + { + infos_.erase(p); + } + auto it = infos_.emplace(std::piecewise_construct, std::forward_as_tuple(p), + std::forward_as_tuple(p, read_initial)); return it.first->second; } } // namespace lo2s diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp index a3384fe9..858f2fb7 100644 --- a/src/trace/trace.cpp +++ b/src/trace/trace.cpp @@ -286,38 +286,30 @@ Trace::~Trace() std::filesystem::create_symlink(trace_name_, symlink_path); } -const otf2::definition::system_tree_node& Trace::intern_process_node(Process process) -{ - if (registry_.has(ByProcess(process))) - { - return registry_.get(ByProcess(process)); - } - else - { - Log::warn() << "Could not find system tree node for " << process; - return system_tree_root_node_; - } -} - -void Trace::add_process(Process parent, Process process, const std::string& name) +void Trace::emplace_process(Process parent, Process process, const std::string& name) { std::lock_guard guard(mutex_); if (registry_.has(ByProcess(process))) { - update_process_name(process, name); + update_process(parent, process, name); return; } else { + auto parent_node = system_tree_root_node_; + + if (parent != NO_PARENT_PROCESS) + { + emplace_process(NO_PARENT_PROCESS, parent, ""); + parent_node = registry_.get(ByProcess(parent)); + } + thread_names_.emplace(std::piecewise_construct, std::forward_as_tuple(process.as_thread()), std::forward_as_tuple(name)); const auto& iname = intern(name); - const auto& parent_node = - (parent == NO_PARENT_PROCESS) ? system_tree_root_node_ : intern_process_node(parent); - const auto& ret = registry_.create( ByProcess(process), iname, intern("process"), parent_node); @@ -334,19 +326,28 @@ void Trace::add_process(Process parent, Process process, const std::string& name } } -void Trace::update_process_name(Process process, const std::string& name) +void Trace::update_process(Process parent, Process process, const std::string& name) { std::lock_guard guard(mutex_); - const auto& iname = intern(name); try { - registry_.get(ByProcess(process)).name(iname); - registry_.get(ByExecutionScope(process.as_scope())) - .name(iname); - registry_.get(ByProcess(process)).name(iname); - registry_.get(ByProcess(process)).name(iname); + auto tree_node = registry_.get(ByProcess(process)); + if (name != "") + { + const auto& iname = intern(name); + tree_node.name(iname); + registry_.get(ByExecutionScope(process.as_scope())) + .name(iname); + registry_.get(ByProcess(process)).name(iname); + registry_.get(ByProcess(process)).name(iname); - update_thread_name(process.as_thread(), name); + update_thread(process.as_thread(), name); + } + if (parent != NO_PARENT_PROCESS && tree_node.parent() == system_tree_root_node_) + { + emplace_process(NO_PARENT_PROCESS, parent); + tree_node.parent(registry_.get(ByProcess(parent))); + } } catch (const std::out_of_range&) { @@ -354,7 +355,7 @@ void Trace::update_process_name(Process process, const std::string& name) } } -void Trace::update_thread_name(Thread thread, const std::string& name) +void Trace::update_thread(Thread thread, const std::string& name) { // TODO we call this function in a hot-loop, locking doesn't sound like a good idea std::lock_guard guard(mutex_); @@ -611,7 +612,8 @@ otf2::definition::metric_class& Trace::metric_class() void Trace::merge_ips(const std::map& new_children, std::map& children, std::vector& mapping_table, - otf2::definition::calling_context& parent, ProcessMap& infos, Process process) + otf2::definition::calling_context& parent, ProcessInfo& info, + MeasurementScope scope) { for (const auto& elem : new_children) { @@ -620,15 +622,7 @@ void Trace::merge_ips(const std::map& new_children, auto& local_children = elem.second.children; LineInfo line_info = LineInfo::for_unknown_function(); - if (infos.has(process, UINT64_MAX)) - { - line_info = infos.get(process, UINT64_MAX).lookup_line_info(ip); - } - else - { - infos.insert(process, 0, false); - line_info = infos.get(process, UINT64_MAX).lookup_line_info(ip); - } + line_info = info.lookup_line_info(scope, ip); Log::trace() << "resolved " << ip << ": " << line_info; auto cctx_it = children.find(ip); @@ -639,11 +633,11 @@ void Trace::merge_ips(const std::map& new_children, auto r = children.emplace(ip, new_cctx); cctx_it = r.first; - if (config().disassemble && infos.has(process, UINT64_MAX) == 1) + if (config().disassemble) { try { - auto instruction = infos.get(process, UINT64_MAX).lookup_instruction(ip); + auto instruction = info.lookup_instruction(scope, ip); Log::trace() << "mapped " << ip << " to " << instruction; registry_.create( @@ -659,7 +653,7 @@ void Trace::merge_ips(const std::map& new_children, auto& cctx = cctx_it->second.cctx; mapping_table.at(local_ref) = cctx.ref(); - merge_ips(local_children, cctx_it->second.children, mapping_table, cctx, infos, process); + merge_ips(local_children, cctx_it->second.children, mapping_table, cctx, info, scope); } } @@ -673,10 +667,10 @@ otf2::definition::mapping_table Trace::merge_calling_contexts(const LocalCctxMap std::vector mappings(local_cctxs.num_cctx()); #endif - // Merge local thread tree into global thread tree for (auto& process_map : local_cctxs.get_threads()) { Process process = process_map.first; + emplace_process(NO_PARENT_PROCESS, process); for (auto& local_thread_cctx : process_map.second) { @@ -689,31 +683,7 @@ otf2::definition::mapping_table Trace::merge_calling_contexts(const LocalCctxMap if (global_thread_cctx == global_thread_cctxs_.end()) { - if (thread != Thread(0)) - { - - if (auto thread_name = thread_names_.find(thread); - thread_name != thread_names_.end()) - { - add_thread(thread, thread_name->second); - } - else - { - if (auto process_name = thread_names_.find(process.as_thread()); - process_name != thread_names_.end()) - { - add_thread(thread, process_name->second); - } - else - { - add_thread(thread, ""); - } - } - } - else - { - add_thread(thread, ""); - } + emplace_thread(thread); } const auto& foo = global_thread_cctxs_.at(thread).cctx.ref(); mappings.at(local_ref.ref) = foo; @@ -722,11 +692,18 @@ otf2::definition::mapping_table Trace::merge_calling_contexts(const LocalCctxMap for (auto& local_process_map : local_cctxs.get_functions()) { - auto& parent = registry_.get( - ByThread(local_process_map.first.as_thread())); + + Process p = local_process_map.first.scope.as_process(); + + auto& parent = registry_.get(ByThread(p.as_thread())); auto ret = calling_context_tree_.emplace(local_process_map.first, std::map()); - merge_ips(local_process_map.second, ret.first->second, mappings, parent, infos, + if (!infos.has(p)) + { + infos.insert(p, false); + } + ProcessInfo& info = infos.get(p); + merge_ips(local_process_map.second, ret.first->second, mappings, parent, info, local_process_map.first); } @@ -771,18 +748,39 @@ Trace::merge_syscall_contexts(const std::set& used_syscalls) mappings); } -void Trace::add_thread_exclusive(Thread thread, const std::string& name, - const std::lock_guard&) +void Trace::emplace_thread_exclusive(Thread thread, const std::string& name, + const std::lock_guard&) { if (registry_.has(ByThread(thread))) { - update_thread_name(thread, name); + update_thread(thread, name); return; } + std::string thread_name = ""; + if (name == "") + { + auto thread_it = thread_names_.find(thread); + if (thread_it != thread_names_.end()) + { + thread_name = thread_it->second; + } + else + { + Process p = groups_.get_parent(thread.as_scope()).as_process(); + auto process_name = thread_names_.find(p.as_thread()); + if (process_name != thread_names_.end()) + { + thread_name = process_name->second; + } + } + } + else + { + thread_name = name; + } thread_names_.emplace(std::piecewise_construct, std::forward_as_tuple(thread), std::forward_as_tuple(name)); - auto& iname = intern(fmt::format("{} ({})", name, thread.as_pid_t())); auto& thread_region = registry_.emplace( @@ -796,11 +794,11 @@ void Trace::add_thread_exclusive(Thread thread, const std::string& name, std::forward_as_tuple(thread_cctx)); } -void Trace::add_thread(Thread thread, const std::string& name) +void Trace::emplace_thread(Thread thread, const std::string& name) { // Lock this to avoid conflict on regions_thread_ with add_monitoring_thread std::lock_guard guard(mutex_); - add_thread_exclusive(thread, name, guard); + emplace_thread_exclusive(thread, name, guard); } void Trace::add_monitoring_thread(Thread thread, const std::string& name, const std::string& group) @@ -828,7 +826,7 @@ void Trace::add_monitoring_thread(Thread thread, const std::string& name, const } } -void Trace::add_threads(const std::unordered_map& thread_map) +void Trace::emplace_threads(const std::unordered_map& thread_map) { Log::debug() << "Adding " << thread_map.size() << " monitored thread(s) to the trace"; @@ -836,7 +834,7 @@ void Trace::add_threads(const std::unordered_map& thread_ma std::lock_guard guard(mutex_); for (const auto& elem : thread_map) { - add_thread_exclusive(elem.first, elem.second, guard); + emplace_thread_exclusive(elem.first, elem.second, guard); } } @@ -879,13 +877,13 @@ const otf2::definition::string& Trace::intern(const std::string& name) return registry_.emplace(ByString(name), name); } -LocalCctxMap& Trace::create_local_cctx_map() +LocalCctxMap& Trace::create_local_cctx_map(MeasurementScope scope) { std::lock_guard guard(local_cctx_maps_mutex_); assert(!local_cctx_maps_finalized_); - return local_cctx_maps_.emplace_back(); + return local_cctx_maps_.emplace_back(scope); } void Trace::merge_calling_contexts(ProcessMap& process_infos) diff --git a/src/util.cpp b/src/util.cpp index 43c9dfaa..5de6af47 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -421,6 +421,7 @@ int timerfd_from_ns(std::chrono::nanoseconds duration) tspec.it_interval.tv_sec = std::chrono::duration_cast(duration).count(); tspec.it_interval.tv_nsec = (duration % std::chrono::seconds(1)).count(); + tspec.it_value.tv_nsec = 1; timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);