-
Notifications
You must be signed in to change notification settings - Fork 771
[SYCL] Introduce XPTI-based tooling for SYCL applications #5389
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
67dc249
9da103d
dd58467
ac51c0a
293d48b
b6a5997
8956b5c
6dcafe5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
add_executable(sycl-prof | ||
main.cpp | ||
) | ||
|
||
target_include_directories(sycl-prof PRIVATE | ||
"${CMAKE_CURRENT_SOURCE_DIR}/../xpti_helpers/" | ||
) | ||
|
||
target_link_libraries(sycl-prof PRIVATE | ||
LLVMSupport | ||
) | ||
|
||
target_compile_options(sycl-prof PRIVATE -fno-exceptions -fno-rtti) | ||
|
||
add_library(sycl_profiler_collector SHARED collector.cpp) | ||
target_compile_definitions(sycl_profiler_collector PRIVATE XPTI_CALLBACK_API_EXPORTS) | ||
target_link_libraries(sycl_profiler_collector PRIVATE xptifw) | ||
if (TARGET OpenCL-Headers) | ||
vladimirlaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
target_link_libraries(sycl_profiler_collector PRIVATE OpenCL-Headers) | ||
endif() | ||
target_include_directories(sycl_profiler_collector PRIVATE | ||
"${sycl_inc_dir}" | ||
"${sycl_src_dir}" | ||
) | ||
|
||
target_compile_options(sycl_profiler_collector PRIVATE -g) | ||
|
||
add_dependencies(sycl-prof sycl_profiler_collector) | ||
add_dependencies(sycl-toolchain sycl-prof) | ||
|
||
include(GNUInstallDirs) | ||
install(TARGETS sycl-prof sycl_profiler_collector | ||
vladimirlaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT sycl-prof | ||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT sycl-prof | ||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT sycl-prof | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
//==-------------- collector.cpp -------------------------------------------==// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "writer.hpp" | ||
#include "xpti/xpti_data_types.h" | ||
|
||
#include <cstdint> | ||
#include <xpti/xpti_trace_framework.h> | ||
|
||
#include <chrono> | ||
#include <memory> | ||
#include <stdio.h> | ||
#include <thread> | ||
#include <unistd.h> | ||
|
||
namespace chrono = std::chrono; | ||
|
||
Writer *GWriter = nullptr; | ||
|
||
struct Measurements { | ||
size_t TID; | ||
size_t PID; | ||
size_t TimeStamp; | ||
}; | ||
|
||
unsigned long process_id() { return static_cast<unsigned long>(getpid()); } | ||
|
||
static Measurements measure() { | ||
size_t TID = std::hash<std::thread::id>{}(std::this_thread::get_id()); | ||
size_t PID = process_id(); | ||
auto Now = chrono::high_resolution_clock::now(); | ||
size_t TS = chrono::time_point_cast<chrono::nanoseconds>(Now) | ||
.time_since_epoch() | ||
.count(); | ||
|
||
return Measurements{TID, PID, TS}; | ||
} | ||
|
||
XPTI_CALLBACK_API void piBeginEndCallback(uint16_t TraceType, | ||
xpti::trace_event_data_t *, | ||
xpti::trace_event_data_t *, | ||
uint64_t /*Instance*/, | ||
const void *UserData); | ||
XPTI_CALLBACK_API void taskBeginEndCallback(uint16_t TraceType, | ||
xpti::trace_event_data_t *, | ||
xpti::trace_event_data_t *, | ||
uint64_t /*Instance*/, | ||
const void *UserData); | ||
XPTI_CALLBACK_API void waitBeginEndCallback(uint16_t TraceType, | ||
xpti::trace_event_data_t *, | ||
xpti::trace_event_data_t *, | ||
uint64_t /*Instance*/, | ||
const void *UserData); | ||
|
||
XPTI_CALLBACK_API void xptiTraceInit(unsigned int /*major_version*/, | ||
unsigned int /*minor_version*/, | ||
const char * /*version_str*/, | ||
const char *StreamName) { | ||
if (GWriter == nullptr) { | ||
GWriter = new JSONWriter(std::getenv("SYCL_PROF_OUT_FILE")); | ||
GWriter->init(); | ||
} | ||
|
||
if (std::string_view(StreamName) == "sycl.pi") { | ||
uint8_t StreamID = xptiRegisterStream(StreamName); | ||
xptiRegisterCallback(StreamID, xpti::trace_function_begin, | ||
piBeginEndCallback); | ||
xptiRegisterCallback(StreamID, xpti::trace_function_end, | ||
piBeginEndCallback); | ||
} else if (std::string_view(StreamName) == "sycl") { | ||
uint8_t StreamID = xptiRegisterStream(StreamName); | ||
xptiRegisterCallback(StreamID, xpti::trace_task_begin, | ||
taskBeginEndCallback); | ||
xptiRegisterCallback(StreamID, xpti::trace_task_end, taskBeginEndCallback); | ||
xptiRegisterCallback(StreamID, xpti::trace_wait_begin, | ||
waitBeginEndCallback); | ||
xptiRegisterCallback(StreamID, xpti::trace_wait_end, waitBeginEndCallback); | ||
xptiRegisterCallback(StreamID, xpti::trace_barrier_begin, | ||
waitBeginEndCallback); | ||
xptiRegisterCallback(StreamID, xpti::trace_barrier_end, | ||
waitBeginEndCallback); | ||
} | ||
} | ||
|
||
XPTI_CALLBACK_API void xptiTraceFinish(const char *) { GWriter->finalize(); } | ||
|
||
XPTI_CALLBACK_API void piBeginEndCallback(uint16_t TraceType, | ||
xpti::trace_event_data_t *, | ||
xpti::trace_event_data_t *, | ||
uint64_t /*Instance*/, | ||
const void *UserData) { | ||
auto [TID, PID, TS] = measure(); | ||
if (TraceType == xpti::trace_function_begin) { | ||
GWriter->writeBegin(static_cast<const char *>(UserData), "Plugin", PID, TID, | ||
TS); | ||
} else { | ||
GWriter->writeEnd(static_cast<const char *>(UserData), "Plugin", PID, TID, | ||
TS); | ||
} | ||
} | ||
|
||
XPTI_CALLBACK_API void taskBeginEndCallback(uint16_t TraceType, | ||
xpti::trace_event_data_t *, | ||
xpti::trace_event_data_t *Event, | ||
uint64_t /*Instance*/, | ||
const void *) { | ||
std::string_view Name = "unknown"; | ||
|
||
xpti::metadata_t *Metadata = xptiQueryMetadata(Event); | ||
for (auto &Item : *Metadata) { | ||
std::string_view Key{xptiLookupString(Item.first)}; | ||
if (Key == "kernel_name" || Key == "memory_object") { | ||
Name = xptiLookupString(Item.second); | ||
} | ||
} | ||
|
||
auto [TID, PID, TS] = measure(); | ||
if (TraceType == xpti::trace_task_begin) { | ||
GWriter->writeBegin(Name, "SYCL", PID, TID, TS); | ||
} else { | ||
GWriter->writeEnd(Name, "SYCL", PID, TID, TS); | ||
} | ||
} | ||
|
||
XPTI_CALLBACK_API void waitBeginEndCallback(uint16_t TraceType, | ||
xpti::trace_event_data_t *, | ||
xpti::trace_event_data_t *, | ||
uint64_t /*Instance*/, | ||
const void *UserData) { | ||
auto [TID, PID, TS] = measure(); | ||
if (TraceType == xpti::trace_wait_begin || | ||
TraceType == xpti::trace_barrier_begin) { | ||
GWriter->writeBegin(static_cast<const char *>(UserData), "SYCL", PID, TID, | ||
TS); | ||
} else { | ||
GWriter->writeEnd(static_cast<const char *>(UserData), "SYCL", PID, TID, | ||
TS); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
//==------------ main.cpp - SYCL Profiler Tool -----------------------------==// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "launch.hpp" | ||
#include "llvm/Support/CommandLine.h" | ||
|
||
#include <iostream> | ||
#include <string> | ||
|
||
using namespace llvm; | ||
|
||
enum OutputFormatKind { JSON }; | ||
|
||
int main(int argc, char **argv, char *env[]) { | ||
cl::opt<OutputFormatKind> OutputFormat( | ||
"format", cl::desc("Set profiler output format:"), | ||
cl::values( | ||
// TODO performance summary | ||
clEnumValN(JSON, "json", | ||
"JSON file, compatible with chrome://tracing"))); | ||
cl::opt<std::string> OutputFilename("o", cl::desc("Specify output filename"), | ||
cl::value_desc("filename"), cl::Required); | ||
cl::opt<std::string> TargetExecutable( | ||
cl::Positional, cl::desc("<target executable>"), cl::Required); | ||
cl::list<std::string> Argv(cl::ConsumeAfter, | ||
cl::desc("<program arguments>...")); | ||
|
||
cl::ParseCommandLineOptions(argc, argv); | ||
|
||
std::vector<std::string> NewEnv; | ||
|
||
{ | ||
size_t I = 0; | ||
while (env[I] != nullptr) | ||
NewEnv.emplace_back(env[I++]); | ||
} | ||
|
||
std::string ProfOutFile = "SYCL_PROF_OUT_FILE=" + OutputFilename; | ||
NewEnv.push_back(ProfOutFile); | ||
NewEnv.push_back("XPTI_FRAMEWORK_DISPATCHER=libxptifw.so"); | ||
NewEnv.push_back("XPTI_SUBSCRIBERS=libsycl_profiler_collector.so"); | ||
NewEnv.push_back("XPTI_TRACE_ENABLE=1"); | ||
|
||
std::vector<std::string> Args; | ||
|
||
Args.push_back(TargetExecutable); | ||
std::copy(Argv.begin(), Argv.end(), std::back_inserter(Args)); | ||
|
||
int Err = launch(TargetExecutable, Args, NewEnv); | ||
|
||
if (Err) { | ||
std::cerr << "Failed to launch target application. Error code " << Err | ||
<< "\n"; | ||
return Err; | ||
} | ||
|
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
//==----------------- writer.hpp -------------------------------------------==// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#pragma once | ||
|
||
#include <fstream> | ||
#include <mutex> | ||
#include <string_view> | ||
|
||
class Writer { | ||
public: | ||
virtual void init() = 0; | ||
virtual void finalize() = 0; | ||
virtual void writeBegin(std::string_view Name, std::string_view Category, | ||
size_t PID, size_t TID, size_t TimeStamp) = 0; | ||
virtual void writeEnd(std::string_view Name, std::string_view Category, | ||
size_t PID, size_t TID, size_t TimeStamp) = 0; | ||
virtual ~Writer() = default; | ||
}; | ||
|
||
class JSONWriter : public Writer { | ||
public: | ||
explicit JSONWriter(const std::string &OutPath) : MOutFile(OutPath) {} | ||
|
||
void init() final { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you worried by your neighbors with these There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choosing between |
||
std::lock_guard _{MWriteMutex}; | ||
|
||
MOutFile << "{\n"; | ||
MOutFile << " \"traceEvents\": [\n"; | ||
} | ||
|
||
void writeBegin(std::string_view Name, std::string_view Category, size_t PID, | ||
size_t TID, size_t TimeStamp) override { | ||
std::lock_guard _{MWriteMutex}; | ||
|
||
if (!MOutFile.is_open()) | ||
return; | ||
|
||
MOutFile << "{\"name\": \"" << Name << "\", "; | ||
MOutFile << "\"cat\": \"" << Category << "\", "; | ||
MOutFile << "\"ph\": \"B\", "; | ||
MOutFile << "\"pid\": \"" << PID << "\", "; | ||
MOutFile << "\"tid\": \"" << TID << "\", "; | ||
MOutFile << "\"ts\": \"" << TimeStamp << "\"},"; | ||
MOutFile << std::endl; | ||
} | ||
|
||
void writeEnd(std::string_view Name, std::string_view Category, size_t PID, | ||
size_t TID, size_t TimeStamp) override { | ||
std::lock_guard _{MWriteMutex}; | ||
|
||
if (!MOutFile.is_open()) | ||
return; | ||
|
||
MOutFile << "{\"name\": \"" << Name << "\", "; | ||
MOutFile << "\"cat\": \"" << Category << "\", "; | ||
MOutFile << "\"ph\": \"E\", "; | ||
MOutFile << "\"pid\": \"" << PID << "\", "; | ||
MOutFile << "\"tid\": \"" << TID << "\", "; | ||
MOutFile << "\"ts\": \"" << TimeStamp << "\"},"; | ||
MOutFile << std::endl; | ||
} | ||
|
||
void finalize() final { | ||
std::lock_guard _{MWriteMutex}; | ||
|
||
if (!MOutFile.is_open()) | ||
return; | ||
|
||
MOutFile << "],\n"; | ||
MOutFile << "\"displayTimeUnit\":\"ns\"\n}\n"; | ||
MOutFile.close(); | ||
} | ||
|
||
~JSONWriter() { finalize(); } | ||
|
||
private: | ||
std::mutex MWriteMutex; | ||
std::ofstream MOutFile; | ||
}; |
Uh oh!
There was an error while loading. Please reload this page.