From c00a3a66a47625ca7706cbd3b89c06ea28be6523 Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Sat, 25 Jul 2020 14:05:44 -0700 Subject: [PATCH 1/2] Adding Google Chrome trace event support --- CMakeLists.txt | 6 +- src/apex/CMakeLists.standalone | 1 + src/apex/apex.cpp | 5 ++ src/apex/apex_types.h | 1 + src/apex/trace_event_listener.cpp | 136 ++++++++++++++++++++++++++++++ src/apex/trace_event_listener.hpp | 55 ++++++++++++ 6 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 src/apex/trace_event_listener.cpp create mode 100644 src/apex/trace_event_listener.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ae65242..88dfcc5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -681,6 +681,11 @@ if(USE_PLUGINS) message(INFO " apex will be built with plugin support.") set(LIBS ${LIBS} ${CMAKE_DL_LIBS}) add_definitions("-DAPEX_USE_PLUGINS") +endif() + +################################################################################ +# Need JSON for writing trace events +################################################################################ git_external(rapidjson https://github.com/miloyip/rapidjson.git @@ -699,7 +704,6 @@ if(USE_PLUGINS) message(FATAL_ERROR " rapidjson not found. This should have been checked out automatically. " "Try manually check out https://github.com/miloyip/rapidjson.git to ${PROJECT_SOURCE_DIR}") endif() -endif() ################################################################################ # Standard Library configuration diff --git a/src/apex/CMakeLists.standalone b/src/apex/CMakeLists.standalone index f43ee5e9..795ac76a 100644 --- a/src/apex/CMakeLists.standalone +++ b/src/apex/CMakeLists.standalone @@ -44,6 +44,7 @@ ${SENSOR_SOURCE} task_identifier.cpp ${tau_SOURCE} thread_instance.cpp +trace_event_listener.cpp utils.cpp ) diff --git a/src/apex/apex.cpp b/src/apex/apex.cpp index cca1cff9..464f542c 100644 --- a/src/apex/apex.cpp +++ b/src/apex/apex.cpp @@ -39,6 +39,7 @@ #include "tau_listener.hpp" #include "profiler_listener.hpp" +#include "trace_event_listener.hpp" #if defined(APEX_DEBUG) || defined(APEX_ERROR_HANDLING) // #define APEX_DEBUG_disabled #include "apex_error_handling.hpp" @@ -260,6 +261,10 @@ void apex::_initialize() listeners.push_back(new otf2_listener()); } #endif + if (apex_options::use_trace_event()) + { + listeners.push_back(new trace_event_listener()); + } /* For the Jupyter support, always enable the concurrency handler. */ #ifndef APEX_WITH_JUPYTER_SUPPORT diff --git a/src/apex/apex_types.h b/src/apex/apex_types.h index 7adafe18..382ae2c2 100644 --- a/src/apex/apex_types.h +++ b/src/apex/apex_types.h @@ -252,6 +252,7 @@ inline unsigned int sc_nprocessors_onln() macro (APEX_OTF2, use_otf2, bool, false) \ macro (APEX_OTF2_TESTING, otf2_testing, bool, false) \ macro (APEX_OTF2_COLLECTIVE_SIZE, otf2_collective_size, int, 1) \ + macro (APEX_TRACE_EVENT, use_trace_event, bool, false) \ macro (APEX_POLICY, use_policy, bool, true) \ macro (APEX_MEASURE_CONCURRENCY, use_concurrency, int, 0) \ macro (APEX_MEASURE_CONCURRENCY_PERIOD, concurrency_period, int, 1000000) \ diff --git a/src/apex/trace_event_listener.cpp b/src/apex/trace_event_listener.cpp new file mode 100644 index 00000000..a8b588fc --- /dev/null +++ b/src/apex/trace_event_listener.cpp @@ -0,0 +1,136 @@ +// Copyright (c) 2014 University of Oregon +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include "trace_event_listener.hpp" +#include "thread_instance.hpp" +#include +#include +#include + +using namespace std; + +namespace apex { + +bool trace_event_listener::_initialized(false); + +trace_event_listener::trace_event_listener (void) : _terminate(false) { + _initialized = true; +} + +void trace_event_listener::on_startup(startup_event_data &data) { + APEX_UNUSED(data); + return; +} + +void trace_event_listener::on_dump(dump_event_data &data) { + APEX_UNUSED(data); + if (!_terminate) { + } + return; +} + +void trace_event_listener::on_shutdown(shutdown_event_data &data) { + APEX_UNUSED(data); + if (!_terminate) { + _terminate = true; + } + return; +} + +void trace_event_listener::on_new_node(node_event_data &data) { + APEX_UNUSED(data); + if (!_terminate) { + // set node id + } + return; +} + +void trace_event_listener::on_new_thread(new_thread_event_data &data) { + APEX_UNUSED(data); + if (!_terminate) { + } + return; +} + +void trace_event_listener::on_exit_thread(event_data &data) { + APEX_UNUSED(data); + if (!_terminate) { + } + return; +} + +inline bool trace_event_listener::_common_start(std::shared_ptr &tt_ptr) { + APEX_UNUSED(tt_ptr); + if (!_terminate) { + } else { + return false; + } + return true; +} + +bool trace_event_listener::on_start(std::shared_ptr &tt_ptr) { + return _common_start(tt_ptr); +} + +bool trace_event_listener::on_resume(std::shared_ptr &tt_ptr) { + return _common_start(tt_ptr); +} + +inline void trace_event_listener::_common_stop(std::shared_ptr &p) { + APEX_UNUSED(p); + if (!_terminate) { + } + return; +} + +void trace_event_listener::on_stop(std::shared_ptr &p) { + return _common_stop(p); +} + +void trace_event_listener::on_yield(std::shared_ptr &p) { + return _common_stop(p); +} + +void trace_event_listener::on_sample_value(sample_value_event_data &data) { + APEX_UNUSED(data); + if (!_terminate) { + } + return; +} + +void trace_event_listener::on_periodic(periodic_event_data &data) { + APEX_UNUSED(data); + if (!_terminate) { + } + return; +} + +void trace_event_listener::on_custom_event(custom_event_data &data) { + APEX_UNUSED(data); + if (!_terminate) { + } + return; +} + +void trace_event_listener::set_node_id(int node_id, int node_count) { + APEX_UNUSED(node_id); + APEX_UNUSED(node_count); +} + +void trace_event_listener::set_metadata(const char * name, const char * value) { + APEX_UNUSED(name); + APEX_UNUSED(value); +} + +/* This function is used by APEX threads so that TAU knows about them. */ +int initialize_worker_thread_for_trace_event(void) { + if (trace_event_listener::initialized()) + { + } + return 0; +} + +}// end namespace + diff --git a/src/apex/trace_event_listener.hpp b/src/apex/trace_event_listener.hpp new file mode 100644 index 00000000..51810b28 --- /dev/null +++ b/src/apex/trace_event_listener.hpp @@ -0,0 +1,55 @@ +// Copyright (c) 2014 University of Oregon +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma once + +#include "event_listener.hpp" +#include + +namespace apex { + +class trace_event_listener : public event_listener { +private: + void _init(void); + bool _terminate; + bool _common_start(std::shared_ptr &tt_ptr); + void _common_stop(std::shared_ptr &p); + static bool _initialized; +public: + trace_event_listener (void); + ~trace_event_listener (void) { }; + static bool initialize_tau(int argc, char** avgv); + inline static bool initialized(void) { return _initialized; } + void on_startup(startup_event_data &data); + void on_dump(dump_event_data &data); + void on_reset(task_identifier * id) + { APEX_UNUSED(id); }; + void on_shutdown(shutdown_event_data &data); + void on_new_node(node_event_data &data); + void on_new_thread(new_thread_event_data &data); + void on_exit_thread(event_data &data); + bool on_start(std::shared_ptr &tt_ptr); + void on_stop(std::shared_ptr &p); + void on_yield(std::shared_ptr &p); + bool on_resume(std::shared_ptr &tt_ptr); + void on_task_complete(std::shared_ptr &tt_ptr) { + APEX_UNUSED(tt_ptr); + }; + void on_sample_value(sample_value_event_data &data); + void on_periodic(periodic_event_data &data); + void on_custom_event(custom_event_data &data); + void on_send(message_event_data &data) { APEX_UNUSED(data); }; + void on_recv(message_event_data &data) { APEX_UNUSED(data); }; + void set_node_id(int node_id, int node_count); + void set_metadata(const char * name, const char * value); + + static void Tau_start_wrapper(const char * name); + static void Tau_stop_wrapper(const char * name); +}; + +int initialize_worker_thread_for_tau(void); + +} + From 635324861dd83bb6f092f0e9247ff3b259665cbb Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Sun, 26 Jul 2020 16:04:30 -0700 Subject: [PATCH 2/2] Working (rudimentary) Google Trace Event support. This support only handles timers, no counters (yet). --- CMakeLists.txt | 6 +- src/apex/apex.cpp | 5 +- src/apex/apex.hpp | 2 + src/apex/profiler.hpp | 26 ++++++-- src/apex/trace_event_listener.cpp | 63 +++++++++++++++++- src/apex/trace_event_listener.hpp | 104 ++++++++++++++++++++---------- src/unit_tests/C/apex_start.c | 4 +- 7 files changed, 159 insertions(+), 51 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 88dfcc5e..9ae65242 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -681,11 +681,6 @@ if(USE_PLUGINS) message(INFO " apex will be built with plugin support.") set(LIBS ${LIBS} ${CMAKE_DL_LIBS}) add_definitions("-DAPEX_USE_PLUGINS") -endif() - -################################################################################ -# Need JSON for writing trace events -################################################################################ git_external(rapidjson https://github.com/miloyip/rapidjson.git @@ -704,6 +699,7 @@ endif() message(FATAL_ERROR " rapidjson not found. This should have been checked out automatically. " "Try manually check out https://github.com/miloyip/rapidjson.git to ${PROJECT_SOURCE_DIR}") endif() +endif() ################################################################################ # Standard Library configuration diff --git a/src/apex/apex.cpp b/src/apex/apex.cpp index 464f542c..07d6897b 100644 --- a/src/apex/apex.cpp +++ b/src/apex/apex.cpp @@ -250,7 +250,7 @@ void apex::_initialize() //write_lock_type l(listener_mutex); this->the_profiler_listener = new profiler_listener(); // this is always the first listener! - listeners.push_back(the_profiler_listener); + listeners.push_back(the_profiler_listener); if (apex_options::use_tau() && tau_loaded) { listeners.push_back(new tau_listener()); @@ -263,7 +263,8 @@ void apex::_initialize() #endif if (apex_options::use_trace_event()) { - listeners.push_back(new trace_event_listener()); + the_trace_event_listener = new trace_event_listener(); + listeners.push_back(the_trace_event_listener); } /* For the Jupyter support, always enable the concurrency handler. */ diff --git a/src/apex/apex.hpp b/src/apex/apex.hpp index 758b40d4..3214bcd9 100644 --- a/src/apex/apex.hpp +++ b/src/apex/apex.hpp @@ -102,6 +102,8 @@ class apex #endif public: profiler_listener * the_profiler_listener; + event_listener * the_trace_event_listener; + event_listener * the_otf2_listener; #if APEX_HAVE_PROC proc_data_reader * pd_reader; #endif diff --git a/src/apex/profiler.hpp b/src/apex/profiler.hpp index 0f6ae25e..f6bd2f1a 100644 --- a/src/apex/profiler.hpp +++ b/src/apex/profiler.hpp @@ -15,6 +15,7 @@ class profiler; #include #include "apex_options.hpp" #include "apex_types.h" +#include "apex_assert.h" #include #include #include "task_wrapper.hpp" @@ -25,7 +26,7 @@ class profiler; #ifdef __INTEL_COMPILER #define CLOCK_TYPE high_resolution_clock #else -#define CLOCK_TYPE steady_clock +#define CLOCK_TYPE system_clock #endif namespace apex { @@ -179,13 +180,30 @@ class profiler { this->is_resume = true; start = MYCLOCK::now(); }; + uint64_t get_start() { + APEX_ASSERT(!is_counter); + using namespace std::chrono; + uint64_t stamp = duration_cast(start.time_since_epoch()).count(); + return stamp; + } + uint64_t get_stop() { + APEX_ASSERT(!is_counter); + using namespace std::chrono; + uint64_t stamp = duration_cast(end.time_since_epoch()).count(); + return stamp; + } + static uint64_t get_time( void ) { + using namespace std::chrono; + uint64_t stamp = duration_cast(MYCLOCK::now().time_since_epoch()).count(); + return stamp; + } double elapsed(void) { if(is_counter) { return value; } else { - std::chrono::duration time_span = - std::chrono::duration_cast>(end - - start); + using namespace std::chrono; + duration time_span = + duration_cast>(end - start); return time_span.count(); } } diff --git a/src/apex/trace_event_listener.cpp b/src/apex/trace_event_listener.cpp index a8b588fc..37cefdc3 100644 --- a/src/apex/trace_event_listener.cpp +++ b/src/apex/trace_event_listener.cpp @@ -5,6 +5,7 @@ #include "trace_event_listener.hpp" #include "thread_instance.hpp" +#include "apex.hpp" #include #include #include @@ -15,7 +16,24 @@ namespace apex { bool trace_event_listener::_initialized(false); -trace_event_listener::trace_event_listener (void) : _terminate(false) { +trace_event_listener::trace_event_listener (void) : _terminate(false), + saved_node_id(apex::instance()->get_node_id()) { + std::stringstream ss; + ss << "trace_events." << saved_node_id << ".json"; + trace.open(ss.str()); + trace << fixed << "{\n"; + trace << "\"displayTimeUnit\": \"ns\",\n"; + trace << "\"traceEvents\": [\n"; + trace << "{\"name\": \"program\", \"cat\": \"PERF\", \"ph\": \"B\", \"pid\": \"" << + saved_node_id << "\", \"tid\": \"0\", \"ts\": \"" << profiler::get_time() << "\"},\n"; + _initialized = true; +} + +trace_event_listener::~trace_event_listener (void) { + trace << "{\"name\": \"program\", \"cat\": \"PERF\", \"ph\": \"E\", \"pid\": \"" << + saved_node_id << "\", \"tid\": \"0\", \"ts\": \"" << profiler::get_time() << "\"}\n"; + trace << "]\n}\n" << std::endl; + trace.close(); _initialized = true; } @@ -62,8 +80,13 @@ void trace_event_listener::on_exit_thread(event_data &data) { } inline bool trace_event_listener::_common_start(std::shared_ptr &tt_ptr) { - APEX_UNUSED(tt_ptr); if (!_terminate) { + _mutex.lock(); + trace << "{\"name\": \"" << tt_ptr->task_id->get_name() + << "\", \"cat\": \"PERF\", \"ph\": \"B\", \"pid\": \"" + << saved_node_id << "\", \"tid\": " << thread_instance::get_id() + << ", \"ts\": \"" << tt_ptr->prof->get_start() << "\"},\n"; + _mutex.unlock(); } else { return false; } @@ -79,8 +102,13 @@ bool trace_event_listener::on_resume(std::shared_ptr &tt_ptr) { } inline void trace_event_listener::_common_stop(std::shared_ptr &p) { - APEX_UNUSED(p); if (!_terminate) { + _mutex.lock(); + trace << "{\"name\": \"" << p->get_task_id()->get_name() + << "\", \"cat\": \"PERF\", \"ph\": \"E\", \"pid\": \"" << saved_node_id + << "\", \"tid\": " << thread_instance::get_id() + << ", \"ts\": \"" << p->get_stop() << "\"},\n"; + _mutex.unlock(); } return; } @@ -124,6 +152,35 @@ void trace_event_listener::set_metadata(const char * name, const char * value) { APEX_UNUSED(value); } +std::string trace_event_listener::make_tid (uint32_t device, uint32_t context, uint32_t stream) { + cuda_thread_node tmp(device, context, stream); + size_t tid; + if (vthread_map.count(tmp) == 0) { + vthread_map.insert(std::pair(tmp,vthread_map.size())); + } + tid = vthread_map[tmp]; + std::stringstream ss; + ss << "GPU: " << tid; + std::string label{ss.str()}; + return label; +} + +void trace_event_listener::on_async_event(uint32_t device, uint32_t context, + uint32_t stream, std::shared_ptr &p) { + if (!_terminate) { + _mutex.lock(); + trace << "{\"name\": \"" << p->get_task_id()->get_name() + << "\", \"cat\": \"PERF\", \"ph\": \"B\", \"pid\": \"" + << saved_node_id << "\", \"tid\": " << make_tid(device, context, stream) + << ", \"ts\": \"" << p->get_start() << "\"},\n"; + trace << "{\"name\": \"" << p->get_task_id()->get_name() + << "\", \"cat\": \"PERF\", \"ph\": \"E\", \"pid\": \"" << saved_node_id + << "\", \"tid\": " << make_tid(device, context, stream) + << ", \"ts\": \"" << p->get_stop() << "\"},\n"; + _mutex.unlock(); + } +} + /* This function is used by APEX threads so that TAU knows about them. */ int initialize_worker_thread_for_trace_event(void) { if (trace_event_listener::initialized()) diff --git a/src/apex/trace_event_listener.hpp b/src/apex/trace_event_listener.hpp index 51810b28..d42a10d0 100644 --- a/src/apex/trace_event_listener.hpp +++ b/src/apex/trace_event_listener.hpp @@ -7,46 +7,80 @@ #include "event_listener.hpp" #include +#include +#include +#include namespace apex { class trace_event_listener : public event_listener { -private: - void _init(void); - bool _terminate; - bool _common_start(std::shared_ptr &tt_ptr); - void _common_stop(std::shared_ptr &p); - static bool _initialized; + + class cuda_thread_node { + public: + uint32_t _device; + uint32_t _context; + uint32_t _stream; + cuda_thread_node(uint32_t device, uint32_t context, uint32_t stream) : + _device(device), _context(context), _stream(stream) { } + bool operator==(const cuda_thread_node &rhs) const { + return (_device==rhs._device && + _context==rhs._context && + _stream==rhs._stream); + } + bool operator<(const cuda_thread_node &rhs) const { + if (_device &tt_ptr); - void on_stop(std::shared_ptr &p); - void on_yield(std::shared_ptr &p); - bool on_resume(std::shared_ptr &tt_ptr); - void on_task_complete(std::shared_ptr &tt_ptr) { - APEX_UNUSED(tt_ptr); - }; - void on_sample_value(sample_value_event_data &data); - void on_periodic(periodic_event_data &data); - void on_custom_event(custom_event_data &data); - void on_send(message_event_data &data) { APEX_UNUSED(data); }; - void on_recv(message_event_data &data) { APEX_UNUSED(data); }; - void set_node_id(int node_id, int node_count); - void set_metadata(const char * name, const char * value); - - static void Tau_start_wrapper(const char * name); - static void Tau_stop_wrapper(const char * name); + trace_event_listener (void); + ~trace_event_listener (void); + static bool initialize_tau(int argc, char** avgv); + inline static bool initialized(void) { return _initialized; } + void on_startup(startup_event_data &data); + void on_dump(dump_event_data &data); + void on_reset(task_identifier * id) + { APEX_UNUSED(id); }; + void on_shutdown(shutdown_event_data &data); + void on_new_node(node_event_data &data); + void on_new_thread(new_thread_event_data &data); + void on_exit_thread(event_data &data); + bool on_start(std::shared_ptr &tt_ptr); + void on_stop(std::shared_ptr &p); + void on_yield(std::shared_ptr &p); + bool on_resume(std::shared_ptr &tt_ptr); + void on_task_complete(std::shared_ptr &tt_ptr) { + APEX_UNUSED(tt_ptr); + }; + void on_sample_value(sample_value_event_data &data); + void on_periodic(periodic_event_data &data); + void on_custom_event(custom_event_data &data); + void on_send(message_event_data &data) { APEX_UNUSED(data); }; + void on_recv(message_event_data &data) { APEX_UNUSED(data); }; + void set_node_id(int node_id, int node_count); + void set_metadata(const char * name, const char * value); + void on_async_event(uint32_t device, uint32_t context, + uint32_t stream, std::shared_ptr &p); + std::string make_tid (uint32_t device, uint32_t context, + uint32_t stream); + +private: + void _init(void); + bool _terminate; + bool _common_start(std::shared_ptr &tt_ptr); + void _common_stop(std::shared_ptr &p); + static bool _initialized; + std::ofstream trace; + std::mutex _mutex; + std::map vthread_map; + int saved_node_id; }; int initialize_worker_thread_for_tau(void); diff --git a/src/unit_tests/C/apex_start.c b/src/unit_tests/C/apex_start.c index d99db052..30e2c981 100644 --- a/src/unit_tests/C/apex_start.c +++ b/src/unit_tests/C/apex_start.c @@ -3,7 +3,7 @@ #include int foo(int i) { - apex_profiler_handle profiler = apex_start(APEX_FUNCTION_ADDRESS, &foo); + apex_profiler_handle profiler = apex_start(APEX_NAME_STRING, (void*)__func__); int j = i * i; apex_stop(profiler); return j; @@ -12,7 +12,7 @@ int foo(int i) { int main (int argc, char** argv) { apex_init("apex_start unit test", 0, 1); apex_set_use_screen_output(1); - apex_profiler_handle profiler = apex_start(APEX_FUNCTION_ADDRESS, &main); + apex_profiler_handle profiler = apex_start(APEX_NAME_STRING, (void*)__func__); int i,j = 0; for (i = 0 ; i < 3 ; i++) j += foo(i);