#ifndef XPU_ZE_STREAM_PROFILER_HPP
#define XPU_ZE_STREAM_PROFILER_HPP
#include "xpu/stream_profiler.hpp"
#include "xpu/ze/context.hpp"
#include <unordered_set>
namespace dnnl {
namespace impl {
namespace xpu {
namespace ze {
class stream_profiler_t : public xpu::stream_profiler_t {
public:
class entry_t {
public:
entry_t() = delete;
entry_t(ze_kernel_timestamp_result_t &kernel_timestamp_result,
uint64_t max_timestamp_value, double timestamp_freq)
: context_(get_timestamp(
kernel_timestamp_result.context, max_timestamp_value))
, freq_(timestamp_freq) {}
uint64_t get_cycles() const { return context_; }
uint64_t get_nsec() const {
return static_cast<uint64_t>(freq_ * get_cycles());
}
private:
uint64_t get_timestamp(
ze_kernel_timestamp_data_t &ts, uint64_t max_timestamp_value) {
return (ts.kernelEnd >= ts.kernelStart)
? (ts.kernelEnd - ts.kernelStart)
: ((max_timestamp_value - ts.kernelStart) + ts.kernelEnd
+ 1);
}
uint64_t context_;
double freq_;
};
stream_profiler_t(const impl::stream_t *stream, double timestamp_freq,
uint64_t max_timestamp_value)
: xpu::stream_profiler_t(stream)
, timestamp_freq_(timestamp_freq)
, max_timestamp_value_(max_timestamp_value) {}
status_t get_info(profiling_data_kind_t data_kind, int *num_entries,
uint64_t *data) const override {
if (!num_entries) return status::invalid_arguments;
bool is_per_kernel
= (data_kind == profiling_data_kind::time_per_kernel);
if (!data) {
if (is_per_kernel) {
*num_entries = (int)events_.size();
return status::success;
}
std::unordered_set<uint64_t> seen;
for (auto &ev : events_)
seen.insert(ev.stamp);
*num_entries = (int)seen.size();
return status::success;
}
std::map<uint64_t, entry_t> stamp2entry;
int idx = 0;
for (auto &ev : events_) {
const ze::event_t &ze_event
= *utils::downcast<ze::event_t *>(ev.event.get());
ze_kernel_timestamp_result_t kernel_timestamp_result;
CHECK(ze::zeEventQueryKernelTimestamp(
ze_event[0], &kernel_timestamp_result));
entry_t entry(kernel_timestamp_result, max_timestamp_value_,
timestamp_freq_);
if (is_per_kernel) {
data[idx++] = entry.get_nsec();
continue;
}
stamp2entry.emplace(ev.stamp, entry);
}
if (is_per_kernel) return status::success;
return get_info_impl(stamp2entry, data_kind, data);
}
private:
stream_profiler_t() = delete;
DNNL_DISALLOW_COPY_AND_ASSIGN(stream_profiler_t);
status_t get_info_impl(const std::map<uint64_t, entry_t> &stamp2entry,
profiling_data_kind_t data_kind, uint64_t *data) const {
int idx = 0;
for (auto &kv : stamp2entry) {
auto &e = kv.second;
switch ((int)data_kind) {
case profiling_data_kind::time: data[idx] = e.get_nsec(); break;
case profiling_data_kind::cycles: {
data[idx] = e.get_cycles();
if (callback_) callback_(kv.first, e.get_nsec());
break;
}
default: assert(!"unexpected data kind");
}
idx++;
}
return status::success;
}
double timestamp_freq_;
uint64_t max_timestamp_value_;
};
} } } }
#endif