Remove global variables from the file plugin

The plugin's file scope global variables destructors could be called
before roctracer_plugin_finalize is called, making the global variables
undefined by the time roctracer_plugin_finalize is called.

To avoid this issue, remove all non-pod global variables from the file
plugin.

Change-Id: I4b620d67d460d9c99adfd81cbf46b0e64540c503
Αυτή η υποβολή περιλαμβάνεται σε:
Laurent Morichetti
2022-08-22 21:20:04 -07:00
γονέας bddb9850de
υποβολή 006ce7b65d
+57 -66
Προβολή Αρχείου
@@ -143,43 +143,48 @@ class file_plugin_t {
class output_file_t { class output_file_t {
public: public:
output_file_t(std::string name) : name_(std::move(name)) {} output_file_t(std::string name) : name_(std::move(name)) {}
~output_file_t() { close(); }
std::string path() const { std::string name() const { return name_; }
std::stringstream ss;
ss << GetPid() << "_" << name_;
return output_prefix_ / ss.str();
}
template <typename T> output_file_t& operator<<(T&& value) { template <typename T> std::ostream& operator<<(T&& value) {
if (!is_open()) open(); if (!is_open()) open();
stream() << std::forward<T>(value); return stream_ << std::forward<T>(value);
return *this;
} }
output_file_t& operator<<(std::ostream& (*func)(std::ostream&)) { std::ostream& operator<<(std::ostream& (*func)(std::ostream&)) {
if (!is_open()) open(); if (!is_open()) open();
stream() << func; return stream_ << func;
return *this;
} }
bool is_open() const { return output_prefix_.empty() || stream_.is_open(); }
bool fail() const { return stream().fail(); }
void open() { void open() {
if (output_prefix_.empty()) return; // If the stream is already in the failed state, there's no need to try to open the file.
stream_.open(path()); if (fail()) return;
}
void close() { const char* output_dir = getenv("ROCP_OUTPUT_DIR");
if (stream_.is_open()) stream_.close();
if (output_dir == nullptr) {
stream_.copyfmt(std::cout);
stream_.clear(std::cout.rdstate());
stream_.basic_ios<char>::rdbuf(std::cout.rdbuf());
return;
}
fs::path output_prefix(output_dir);
if (!fs::is_directory(fs::status(output_prefix))) {
if (!stream_.fail()) warning("Cannot open output directory '%s'\n", output_dir);
stream_.setstate(std::ios_base::failbit);
return;
}
std::stringstream ss;
ss << GetPid() << "_" << name_;
stream_.open(output_prefix / ss.str());
} }
bool is_open() const { return stream_.is_open(); }
bool fail() const { return stream_.fail(); }
private: private:
std::ostream& stream() { return output_prefix_.empty() ? std::cout : stream_; }
const std::ostream& stream() const {
return output_prefix_.empty() ? const_cast<const std::ostream&>(std::cout) : stream_;
}
const std::string name_; const std::string name_;
std::ofstream stream_; std::ofstream stream_;
}; };
@@ -191,7 +196,6 @@ class file_plugin_t {
case ACTIVITY_DOMAIN_HSA_API: case ACTIVITY_DOMAIN_HSA_API:
return &hsa_api_file_; return &hsa_api_file_;
case ACTIVITY_DOMAIN_HIP_API: case ACTIVITY_DOMAIN_HIP_API:
case ACTIVITY_DOMAIN_EXT_API:
return &hip_api_file_; return &hip_api_file_;
case ACTIVITY_DOMAIN_HIP_OPS: case ACTIVITY_DOMAIN_HIP_OPS:
return &hip_activity_file_; return &hip_activity_file_;
@@ -211,7 +215,6 @@ class file_plugin_t {
public: public:
file_plugin_t() { file_plugin_t() {
// Dumping HSA handles for agents // Dumping HSA handles for agents
output_file_t hsa_handles("hsa_handles.txt"); output_file_t hsa_handles("hsa_handles.txt");
[[maybe_unused]] hsa_status_t status = hsa_iterate_agents( [[maybe_unused]] hsa_status_t status = hsa_iterate_agents(
@@ -229,7 +232,7 @@ class file_plugin_t {
&hsa_handles); &hsa_handles);
assert(status == HSA_STATUS_SUCCESS && "failed to iterate HSA agents"); assert(status == HSA_STATUS_SUCCESS && "failed to iterate HSA agents");
if (hsa_handles.fail()) { if (hsa_handles.fail()) {
warning("Cannot write to '%s'\n", hsa_handles.path().c_str()); warning("Cannot write to '%s'\n", hsa_handles.name().c_str());
return; return;
} }
@@ -240,10 +243,11 @@ class file_plugin_t {
CHECK_ROCTRACER(roctracer_get_timestamp(&app_begin_timestamp)); CHECK_ROCTRACER(roctracer_get_timestamp(&app_begin_timestamp));
begin_ts << std::dec << app_begin_timestamp << std::endl; begin_ts << std::dec << app_begin_timestamp << std::endl;
if (begin_ts.fail()) { if (begin_ts.fail()) {
warning("Cannot write to '%s'\n", begin_ts.path().c_str()); warning("Cannot write to '%s'\n", begin_ts.name().c_str());
return; return;
} }
is_valid_ = true;
valid_ = true;
} }
int write_callback_record(const roctracer_record_t* record, const void* callback_data) { int write_callback_record(const roctracer_record_t* record, const void* callback_data) {
@@ -289,14 +293,6 @@ class file_plugin_t {
<< data->correlation_id << std::endl; << data->correlation_id << std::endl;
break; break;
} }
case ACTIVITY_DOMAIN_EXT_API: {
output_file = get_output_file(ACTIVITY_DOMAIN_EXT_API);
*output_file << std::dec << record->begin_ns << ":" << record->end_ns << " "
<< record->process_id << ":" << record->thread_id << " MARK"
<< "(name(" << record->mark_message << "))" << std::endl;
break;
[[fallthrough]];
}
default: default:
warning("write_callback_record: ignored record for domain %d", record->domain); warning("write_callback_record: ignored record for domain %d", record->domain);
break; break;
@@ -342,56 +338,51 @@ class file_plugin_t {
return 0; return 0;
} }
bool is_valid() const { return is_valid_; } bool is_valid() const { return valid_; }
private: private:
bool is_valid_{false}; bool valid_{false};
output_file_t roctx_file_{"roctx_trace.txt"}, hsa_api_file_{"hsa_api_trace.txt"}, output_file_t roctx_file_{"roctx_trace.txt"}, hsa_api_file_{"hsa_api_trace.txt"},
hip_api_file_{"hip_api_trace.txt"}, hip_activity_file_{"hcc_ops_trace.txt"}, hip_api_file_{"hip_api_trace.txt"}, hip_activity_file_{"hcc_ops_trace.txt"},
hsa_async_copy_file_{"async_copy_trace.txt"}, pc_sample_file_{"pcs_trace.txt"}; hsa_async_copy_file_{"async_copy_trace.txt"}, pc_sample_file_{"pcs_trace.txt"};
static fs::path output_prefix_;
}; };
fs::path file_plugin_t::output_prefix_ = []() { file_plugin_t* file_plugin = nullptr;
const char* output_dir = getenv("ROCP_OUTPUT_DIR");
if (output_dir == nullptr) return "";
if (!fs::is_directory(fs::status(output_dir)))
fatal("Cannot open output directory specified by ROCP_OUTPUT_DIR!\n");
return output_dir;
}();
} // namespace } // namespace
std::unique_ptr<file_plugin_t> file_plugin; ROCTRACER_EXPORT int roctracer_plugin_initialize(uint32_t roctracer_major_version,
uint32_t roctracer_minor_version) {
int roctracer_plugin_initialize(uint32_t roctracer_major_version,
uint32_t roctracer_minor_version) {
if (roctracer_major_version != ROCTRACER_VERSION_MAJOR || if (roctracer_major_version != ROCTRACER_VERSION_MAJOR ||
roctracer_minor_version < ROCTRACER_VERSION_MINOR) roctracer_minor_version < ROCTRACER_VERSION_MINOR)
return -1; return -1;
if (file_plugin) return -1; if (file_plugin != nullptr) return -1;
file_plugin = std::make_unique<file_plugin_t>();
if (!file_plugin->is_valid()) { file_plugin = new file_plugin_t();
file_plugin.reset(); if (file_plugin->is_valid()) return 0;
return -1;
} // The plugin failed to initialied, destroy it and return an error.
return 0; delete file_plugin;
file_plugin = nullptr;
return -1;
} }
void roctracer_plugin_finalize() { file_plugin.reset(); } ROCTRACER_EXPORT void roctracer_plugin_finalize() {
if (!file_plugin) return;
delete file_plugin;
file_plugin = nullptr;
}
int roctracer_plugin_write_callback_record(const roctracer_record_t* record, ROCTRACER_EXPORT int roctracer_plugin_write_callback_record(const roctracer_record_t* record,
const void* callback_data) { const void* callback_data) {
if (!file_plugin || !file_plugin->is_valid()) return -1; if (!file_plugin || !file_plugin->is_valid()) return -1;
return file_plugin->write_callback_record(record, callback_data); return file_plugin->write_callback_record(record, callback_data);
} }
int roctracer_plugin_write_activity_records(const roctracer_record_t* begin, ROCTRACER_EXPORT int roctracer_plugin_write_activity_records(const roctracer_record_t* begin,
const roctracer_record_t* end) { const roctracer_record_t* end) {
if (!file_plugin || !file_plugin->is_valid()) return -1; if (!file_plugin || !file_plugin->is_valid()) return -1;
return file_plugin->write_activity_records(begin, end); return file_plugin->write_activity_records(begin, end);
} }