Skip to content

Commit 6e418b6

Browse files
andrew0917Andrew Luo
andauthored
[VitisAI] pass base timestamp for vitisai profiling (microsoft#27808)
### Description Pass base timestamp for vitisai profiling Notify EP that profiling has started with the base timestamp (in nanoseconds since epoch) The VitisAI EP can use this to: 1. Calculate relative timestamps (event_ts - base_ts) for the profiling timeline 2. Store the absolute base timestamp if needed for other purposes ### Motivation and Context Due to onnxruntime default profiling json file just have the offset timestamp, it doesn't provider the base timestamp for VitisAI EP, To combine the VaitisAI timeline profiling info and the onnxruntime default profiling json file info, We need pass the timestamp for VitisAI EP. --------- Signed-off-by: Andrew Luo <junpengl@amd.com> Co-authored-by: Andrew Luo <junpengl@amd.com>
1 parent cf805d3 commit 6e418b6

3 files changed

Lines changed: 136 additions & 25 deletions

File tree

onnxruntime/core/providers/vitisai/imp/global_api.cc

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,16 @@ struct OrtVitisAIEpAPI {
9393
const std::vector<std::unique_ptr<vaip_core::ExecutionProvider>>& eps,
9494
const char* const* keys,
9595
const char* const* values, size_t kv_len) = nullptr;
96+
void (*profiler_start)(uint64_t profiling_start_time_us) = nullptr;
97+
void (*profiler_stop)() = nullptr;
98+
// v1: Original 5-element EventInfo
9699
void (*profiler_collect)(
97100
std::vector<EventInfo>& api_events,
98101
std::vector<EventInfo>& kernel_events) = nullptr;
102+
// v2: Extended 6-element EventInfoV2 with args
103+
void (*profiler_collect_v2)(
104+
std::vector<EventInfoV2>& api_events,
105+
std::vector<EventInfoV2>& kernel_events) = nullptr;
99106
const char* (*get_compiled_model_compatibility_info)(
100107
const std::vector<std::unique_ptr<vaip_core::ExecutionProvider>>* eps,
101108
const void* graph_viewer) = nullptr;
@@ -144,7 +151,10 @@ struct OrtVitisAIEpAPI {
144151
}
145152
std::ignore = env.GetSymbolFromLibrary(handle_, "vaip_get_version",
146153
(void**)&vaip_get_version);
154+
std::ignore = env.GetSymbolFromLibrary(handle_, "profiler_start", (void**)&profiler_start);
155+
std::ignore = env.GetSymbolFromLibrary(handle_, "profiler_stop", (void**)&profiler_stop);
147156
std::ignore = env.GetSymbolFromLibrary(handle_, "profiler_collect", (void**)&profiler_collect);
157+
std::ignore = env.GetSymbolFromLibrary(handle_, "profiler_collect_v2", (void**)&profiler_collect_v2);
148158
std::ignore = env.GetSymbolFromLibrary(handle_, "get_compiled_model_compatibility_info", (void**)&get_compiled_model_compatibility_info);
149159
std::ignore = env.GetSymbolFromLibrary(handle_, "validate_compiled_model_compatibility_info", (void**)&validate_compiled_model_compatibility_info);
150160
ORT_THROW_IF_ERROR(env.GetSymbolFromLibrary(handle_, "create_ep_context_nodes", (void**)&create_ep_context_nodes));
@@ -176,13 +186,16 @@ struct OrtVitisAIEpAPI {
176186
compile_onnx_model_vitisai_ep_v4 = nullptr;
177187
vaip_execution_provider_deletor = [](std::vector<std::unique_ptr<vaip_core::ExecutionProvider>>* p) noexcept { delete p; };
178188
vaip_get_version = nullptr;
179-
profiler_collect = nullptr;
180189
get_compiled_model_compatibility_info = nullptr;
181190
validate_compiled_model_compatibility_info = nullptr;
182191
create_ep_context_nodes = nullptr;
183192
vitisai_ep_on_run_start = nullptr;
184193
vitisai_ep_set_ep_dynamic_options = nullptr;
185194
deinitialize_onnxruntime_vitisai_ep = nullptr;
195+
profiler_start = nullptr;
196+
profiler_stop = nullptr;
197+
profiler_collect = nullptr;
198+
profiler_collect_v2 = nullptr;
186199
}
187200
}
188201

@@ -197,6 +210,18 @@ static vaip_core::OrtApiForVaip the_global_api;
197210
std::shared_ptr<KernelRegistry> get_kernel_registry_vitisaiep() { return s_kernel_registry_vitisaiep; }
198211
const std::vector<OrtCustomOpDomain*>& get_domains_vitisaiep() { return s_domains_vitisaiep; }
199212

213+
void profiler_start(uint64_t profiling_start_time_us) {
214+
if (s_library_vitisaiep.profiler_start) {
215+
s_library_vitisaiep.profiler_start(profiling_start_time_us);
216+
}
217+
}
218+
219+
void profiler_stop() {
220+
if (s_library_vitisaiep.profiler_stop) {
221+
s_library_vitisaiep.profiler_stop();
222+
}
223+
}
224+
200225
void profiler_collect(
201226
std::vector<EventInfo>& api_events,
202227
std::vector<EventInfo>& kernel_events) {
@@ -205,6 +230,16 @@ void profiler_collect(
205230
}
206231
}
207232

233+
bool profiler_collect_v2(
234+
std::vector<EventInfoV2>& api_events,
235+
std::vector<EventInfoV2>& kernel_events) {
236+
if (s_library_vitisaiep.profiler_collect_v2) {
237+
s_library_vitisaiep.profiler_collect_v2(api_events, kernel_events);
238+
return true;
239+
}
240+
return false;
241+
}
242+
208243
std::string get_compiled_model_compatibility_info(
209244
const std::vector<std::unique_ptr<vaip_core::ExecutionProvider>>& eps,
210245
const onnxruntime::GraphViewer& graph_viewer) {

onnxruntime/core/providers/vitisai/include/vaip/global_api.h

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,19 @@ int vitisai_ep_set_ep_dynamic_options(
2727
const std::vector<std::unique_ptr<vaip_core::ExecutionProvider>>& eps,
2828
const char* const* keys,
2929
const char* const* values, size_t kv_len);
30+
31+
// Notify EP that profiling has started with the base timestamp (in microseconds since epoch)
32+
// The EP can use this to:
33+
// 1. Calculate relative timestamps (event_ts - base_ts) for the profiling timeline
34+
// 2. Store the absolute base timestamp if needed for other purposes
35+
void profiler_start(uint64_t profiling_start_time_us);
36+
37+
// Notify EP that profiling has stopped
38+
void profiler_stop();
39+
3040
/**
31-
* Replace EventRecord with std::tuple<std::string, int ,int, long long, long long>,
32-
* because EventRecord is defined in profiler_common.h which is used inside onnxruntime.
33-
* However, profiler_collect function will call vitis ep which can't include profiler_common.h.
41+
* EventInfo: Original 5-element tuple (v1 API)
42+
* Kept for backward compatibility with older vaip versions.
3443
*/
3544
using EventInfo = std::tuple<
3645
std::string, // name
@@ -42,6 +51,28 @@ using EventInfo = std::tuple<
4251
void profiler_collect(
4352
std::vector<EventInfo>& api_events,
4453
std::vector<EventInfo>& kernel_events);
54+
55+
/**
56+
* EventInfoV2: Extended 6-element tuple with args map (v2 API)
57+
* 6th element: args map for extended metadata (subgraph_name, flow_type, kernel_idx)
58+
*/
59+
using EventInfoV2 = std::tuple<
60+
std::string, // name
61+
int, // pid
62+
int, // tid
63+
long long, // timestamp
64+
long long, // duration
65+
std::unordered_map<std::string, std::string> // args
66+
>;
67+
68+
// v2 API
69+
// Returns true if the v2 collector symbol was present in the loaded VAIP
70+
// library (i.e. the EP is v2-capable). Returns false if the symbol is not
71+
// available, in which case callers should fall back to profiler_collect (v1).
72+
bool profiler_collect_v2(
73+
std::vector<EventInfoV2>& api_events,
74+
std::vector<EventInfoV2>& kernel_events);
75+
4576
std::unique_ptr<onnxruntime::IExecutionProvider>
4677
CreateExecutionProviderFromAnotherEp(const std::string& lib, const OrtSessionOptions& session_options,
4778
std::unordered_map<std::string, std::string>& provider_options);

onnxruntime/core/providers/vitisai/vitisai_profiler.cc

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,82 @@ namespace profiling {
1111
#if defined(USE_VITISAI)
1212

1313
bool VitisaiProfiler::StartProfiling(TimePoint tp) {
14+
// Notify VAIP EP that profiling has started with base timestamp
15+
profiler_start(std::chrono::duration_cast<std::chrono::microseconds>(
16+
tp.time_since_epoch())
17+
.count());
1418
return true;
1519
}
1620

1721
void VitisaiProfiler::EndProfiling(TimePoint tp, Events& events) {
22+
// Notify VAIP EP that profiling has stopped
23+
// Contract: the VAIP EP must preserve any pending/buffered event data after
24+
// profiler_stop() returns, so that the subsequent profiler_collect[_v2]()
25+
// call below can still retrieve the full set of recorded events. The EP is
26+
// expected to release that buffered data only after collection completes
27+
// (or on the next profiler_start()).
28+
profiler_stop();
29+
1830
auto time_point =
1931
std::chrono::duration_cast<std::chrono::microseconds>(tp.time_since_epoch()).count();
2032

21-
std::vector<EventInfo> api_events;
22-
std::vector<EventInfo> kernel_events;
23-
profiler_collect(api_events, kernel_events);
33+
// Try v2 first
34+
// Use the free function wrappers which internally null-check the pointers.
35+
std::vector<EventInfoV2> api_events_v2;
36+
std::vector<EventInfoV2> kernel_events_v2;
37+
const bool v2_available = profiler_collect_v2(api_events_v2, kernel_events_v2);
2438

25-
InlinedHashMap<std::string, std::string> event_args;
39+
if (v2_available) {
40+
for (auto& a : api_events_v2) {
41+
auto& src_args = std::get<5>(a);
42+
decltype(EventRecord::args) args(src_args.begin(), src_args.end());
43+
events.emplace_back(EventCategory::API_EVENT,
44+
std::get<1>(a),
45+
std::get<2>(a),
46+
std::get<0>(a),
47+
std::get<3>(a) - time_point,
48+
std::get<4>(a),
49+
std::move(args));
50+
}
2651

27-
for (auto& a : api_events) {
28-
events.emplace_back(EventCategory::API_EVENT,
29-
std::get<1>(a), // pid
30-
std::get<2>(a), // tid
31-
std::get<0>(a), // name
32-
std::get<3>(a) - time_point, // timestamp
33-
std::get<4>(a), // duration
34-
event_args);
35-
}
52+
for (auto& k : kernel_events_v2) {
53+
auto& src_args = std::get<5>(k);
54+
decltype(EventRecord::args) args(src_args.begin(), src_args.end());
55+
events.emplace_back(EventCategory::KERNEL_EVENT,
56+
std::get<1>(k),
57+
std::get<2>(k),
58+
std::get<0>(k),
59+
std::get<3>(k) - time_point,
60+
std::get<4>(k),
61+
std::move(args));
62+
}
63+
} else {
64+
// Fall back to v1 API
65+
std::vector<EventInfo> api_events;
66+
std::vector<EventInfo> kernel_events;
67+
profiler_collect(api_events, kernel_events);
68+
69+
decltype(EventRecord::args) event_args;
70+
71+
for (auto& a : api_events) {
72+
events.emplace_back(EventCategory::API_EVENT,
73+
std::get<1>(a),
74+
std::get<2>(a),
75+
std::get<0>(a),
76+
std::get<3>(a) - time_point,
77+
std::get<4>(a),
78+
event_args);
79+
}
3680

37-
for (auto& k : kernel_events) {
38-
events.emplace_back(EventCategory::KERNEL_EVENT,
39-
std::get<1>(k),
40-
std::get<2>(k),
41-
std::get<0>(k),
42-
std::get<3>(k) - time_point,
43-
std::get<4>(k),
44-
event_args);
81+
for (auto& k : kernel_events) {
82+
events.emplace_back(EventCategory::KERNEL_EVENT,
83+
std::get<1>(k),
84+
std::get<2>(k),
85+
std::get<0>(k),
86+
std::get<3>(k) - time_point,
87+
std::get<4>(k),
88+
event_args);
89+
}
4590
}
4691
}
4792

0 commit comments

Comments
 (0)