Files
rocm-systems/src/library.cpp
T

242 rivejä
6.6 KiB
C++
Raaka Normaali näkymä Historia

2021-08-06 13:08:57 -05:00
#include <cstdint>
#include <cstdio>
#include <fstream>
#include <memory>
#include <perfetto.h>
#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <utility>
#include <vector>
#include "timemory/backends/process.hpp"
#include "timemory/environment.hpp"
#include "timemory/mpl/apply.hpp"
#if !defined(JOIN)
# define JOIN(...) tim::mpl::apply<std::string>::join(__VA_ARGS__)
#endif
PERFETTO_DEFINE_CATEGORIES(
perfetto::Category("hosttrace").SetDescription("Function trace"));
extern "C" void
hosttrace_trace_finalize();
namespace
{
bool
get_debug()
{
static bool _v = tim::get_env("HOSTTRACE_DEBUG", false);
return _v;
}
auto
ensure_finalization()
{
if(get_debug())
fprintf(stderr, "[%s]\n", __FUNCTION__);
return tim::scope::destructor{ []() { hosttrace_trace_finalize(); } };
}
auto&
get_trace_session()
{
static std::unique_ptr<perfetto::TracingSession> _session{};
return _session;
}
enum class State : unsigned short
{
PreInit = 0,
Active,
Finalized
};
auto&
get_state()
{
static State _v{ State::PreInit };
return _v;
}
auto&
get_output_filename()
{
static auto _v = []() {
auto _tmp = tim::get_env<std::string>(
"HOSTTRACE_OUTPUT_FILE",
JOIN('/', tim::get_env<std::string>("PWD", ".", false),
"hosttrace.perfetto-trace-%p"));
auto _pos = _tmp.find("%p");
if(_pos != std::string::npos)
_tmp.replace(_pos, 2, std::to_string(tim::process::get_id()));
return _tmp;
}();
return _v;
}
auto&
get_backend()
{
// select inprocess, system, or both (i.e. all)
static auto _v = tim::get_env_choice<std::string>(
"HOSTTRACE_BACKEND",
tim::get_env("HOSTTRACE_BACKEND_SYSTEM", false, false)
? "system" // if HOSTTRACE_BACKEND_SYSTEM is true, default to system.
: "inprocess", // Otherwise, default to inprocess
{ "inprocess", "system", "all" });
return _v;
}
auto
is_system_backend()
{
// if get_backend() returns 'system' or 'all', this is true
return (get_backend() != "inprocess");
}
bool
hosttrace_init_perfetto()
{
if(get_debug())
fprintf(stderr, "[%s]\n", __FUNCTION__);
if(get_state() != State::PreInit)
return false;
// environment settings
auto shmem_size_hint = tim::get_env<size_t>("HOSTTRACE_SHMEM_SIZE_HINT_KB", 40960);
auto buffer_size = tim::get_env<size_t>("HOSTTRACE_BUFFER_SIZE_KB", 1024000);
perfetto::TracingInitArgs args{};
perfetto::TraceConfig cfg{};
perfetto::protos::gen::TrackEventConfig track_event_cfg{};
cfg.add_buffers()->set_size_kb(buffer_size);
auto* ds_cfg = cfg.add_data_sources()->mutable_config();
ds_cfg->set_name("track_event");
ds_cfg->set_track_event_config_raw(track_event_cfg.SerializeAsString());
args.shmem_size_hint_kb = shmem_size_hint;
if(get_backend() != "inprocess")
args.backends |= perfetto::kSystemBackend;
if(get_backend() != "system")
args.backends |= perfetto::kInProcessBackend;
perfetto::Tracing::Initialize(args);
perfetto::TrackEvent::Register();
(void) get_output_filename();
tim::print_env(std::cerr);
if(!is_system_backend())
{
auto& tracing_session = get_trace_session();
tracing_session = perfetto::Tracing::NewTrace();
tracing_session->Setup(cfg);
tracing_session->StartBlocking();
}
get_state() = State::Active;
// if static objects are destroyed in the inverse order of when they are
// created this should ensure that finalization is called before perfetto
// ends the tracing session
static auto _ensure_finalization = ensure_finalization();
return true;
}
} // namespace
extern "C"
{
void hosttrace_push_trace(const char* name)
{
if(get_debug())
fprintf(stderr, "[%s] %s\n", __FUNCTION__, name);
// return if not active
if(get_state() != State::Active && !hosttrace_init_perfetto())
return;
TRACE_EVENT_BEGIN("hosttrace", perfetto::StaticString(name));
}
void hosttrace_pop_trace(const char* name)
{
if(get_debug())
fprintf(stderr, "[%s] %s\n", __FUNCTION__, name);
// return if not active
if(get_state() != State::Active)
return;
TRACE_EVENT_END("hosttrace");
}
void hosttrace_trace_init(const char*, bool, const char*)
{
if(get_debug())
fprintf(stderr, "[%s]\n", __FUNCTION__);
hosttrace_init_perfetto();
}
void hosttrace_trace_finalize(void)
{
if(get_debug())
fprintf(stderr, "[%s]\n", __FUNCTION__);
if(get_state() != State::Active)
return;
get_state() = State::Finalized;
if(!is_system_backend())
{
// Make sure the last event is closed for this example.
perfetto::TrackEvent::Flush();
auto& tracing_session = get_trace_session();
tracing_session->StopBlocking();
std::vector<char> trace_data{ tracing_session->ReadTraceBlocking() };
if(trace_data.empty())
{
fprintf(stderr,
"[%s]> trace data is empty. File '%s' will not be written...\n",
__FUNCTION__, get_output_filename().c_str());
return;
}
// Write the trace into a file.
fprintf(stderr, "[%s]> Outputting '%s'. Trace data: %lu bytes...\n",
__FUNCTION__, get_output_filename().c_str(),
(unsigned long) trace_data.size());
std::ofstream output{};
output.open(get_output_filename(), std::ios::out | std::ios::binary);
if(!output)
fprintf(stderr, "[%s]> Error opening '%s'...\n", __FUNCTION__,
get_output_filename().c_str());
else
output.write(&trace_data[0], trace_data.size());
output.close();
}
}
void hosttrace_trace_set_env(const char* env_name, const char* env_val)
{
if(get_debug())
fprintf(stderr, "[%s] Setting env: %s=%s\n", __FUNCTION__, env_name, env_val);
tim::set_env(env_name, env_val, 0);
}
}
namespace
{
// if static objects are destroyed randomly (relatively uncommon behavior)
// this might call finalization before perfetto ends the tracing session
// but static variable in hosttrace_init_perfetto is more likely
auto _ensure_finalization = ensure_finalization();
} // namespace
PERFETTO_TRACK_EVENT_STATIC_STORAGE();