1 /*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9 #include <gtest/gtest.h>
10 #include <cstdio>
11
12 #include <executorch/devtools/etdump/etdump_flatcc.h>
13 #include <executorch/devtools/etdump/etdump_schema_flatcc_builder.h>
14 #include <executorch/devtools/etdump/etdump_schema_flatcc_reader.h>
15 #include <executorch/runtime/core/exec_aten/testing_util/tensor_factory.h>
16 #include <executorch/runtime/core/span.h>
17 #include <executorch/runtime/platform/runtime.h>
18 #include <executorch/test/utils/DeathTest.h>
19 #include <cstdint>
20 #include <cstring>
21 #include <memory>
22
23 using ::exec_aten::ScalarType;
24 using ::exec_aten::Tensor;
25 using ::executorch::etdump::ETDumpGen;
26 using ::executorch::etdump::ETDumpResult;
27 using ::executorch::runtime::AllocatorID;
28 using ::executorch::runtime::ArrayRef;
29 using ::executorch::runtime::BoxedEvalueList;
30 using ::executorch::runtime::DelegateDebugIdType;
31 using ::executorch::runtime::EValue;
32 using ::executorch::runtime::EventTracerEntry;
33 using ::executorch::runtime::LoggedEValueType;
34 using ::executorch::runtime::Span;
35 using ::executorch::runtime::Tag;
36 using ::executorch::runtime::testing::TensorFactory;
37
38 class ProfilerETDumpTest : public ::testing::Test {
39 protected:
SetUp()40 void SetUp() override {
41 torch::executor::runtime_init();
42 etdump_gen[0] = new ETDumpGen();
43 const size_t buf_size = 1024 * 1024;
44 buf = (uint8_t*)malloc(buf_size * sizeof(uint8_t));
45 etdump_gen[1] = new ETDumpGen(Span<uint8_t>(buf, buf_size));
46 }
47
TearDown()48 void TearDown() override {
49 delete etdump_gen[0];
50 delete etdump_gen[1];
51 free(buf);
52 }
53
54 ETDumpGen* etdump_gen[2];
55 uint8_t* buf = nullptr;
56 };
57
TEST_F(ProfilerETDumpTest,SingleProfileEvent)58 TEST_F(ProfilerETDumpTest, SingleProfileEvent) {
59 for (size_t i = 0; i < 2; i++) {
60 etdump_gen[i]->create_event_block("test_block");
61 EventTracerEntry entry = etdump_gen[i]->start_profiling("test_event", 0, 1);
62 etdump_gen[i]->end_profiling(entry);
63
64 ETDumpResult result = etdump_gen[i]->get_etdump_data();
65 ASSERT_TRUE(result.buf != nullptr);
66 ASSERT_TRUE(result.size != 0);
67
68 size_t size = 0;
69 void* buf = flatbuffers_read_size_prefix(result.buf, &size);
70 etdump_ETDump_table_t etdump = etdump_ETDump_as_root_with_identifier(
71 buf, etdump_ETDump_file_identifier);
72
73 ASSERT_NE(etdump, nullptr);
74 EXPECT_EQ(etdump_ETDump_version(etdump), ETDUMP_VERSION);
75
76 etdump_RunData_vec_t run_data_vec = etdump_ETDump_run_data(etdump);
77 EXPECT_EQ(
78 etdump_gen[i]->get_num_blocks(), etdump_RunData_vec_len(run_data_vec));
79
80 etdump_RunData_table_t run_data_single_prof =
81 etdump_RunData_vec_at(run_data_vec, 0);
82 EXPECT_EQ(
83 std::string(
84 etdump_RunData_name(run_data_single_prof),
85 strlen(etdump_RunData_name(run_data_single_prof))),
86 "test_block");
87
88 if (!etdump_gen[i]->is_static_etdump()) {
89 free(result.buf);
90 }
91 }
92 }
93
TEST_F(ProfilerETDumpTest,MultipleProfileEvent)94 TEST_F(ProfilerETDumpTest, MultipleProfileEvent) {
95 for (size_t i = 0; i < 2; i++) {
96 etdump_gen[i]->create_event_block("test_block");
97
98 // Create the profile events and then add the actual profile events in
99 // reverse.
100 EventTracerEntry entry_1 =
101 etdump_gen[i]->start_profiling("test_event_1", 0, 1);
102 EventTracerEntry entry_2 =
103 etdump_gen[i]->start_profiling("test_event_2", 0, 2);
104
105 etdump_gen[i]->end_profiling(entry_2);
106 etdump_gen[i]->end_profiling(entry_1);
107 }
108 }
109
TEST_F(ProfilerETDumpTest,EmptyBlocks)110 TEST_F(ProfilerETDumpTest, EmptyBlocks) {
111 for (size_t i = 0; i < 2; i++) {
112 etdump_gen[i]->create_event_block("test_block");
113 etdump_gen[i]->create_event_block("test_block_1");
114 etdump_gen[i]->create_event_block("test_block_2");
115
116 EventTracerEntry entry =
117 etdump_gen[i]->start_profiling("test_event_1", 0, 1);
118 etdump_gen[i]->end_profiling(entry);
119
120 ETDumpResult result = etdump_gen[i]->get_etdump_data();
121 ASSERT_TRUE(result.buf != nullptr);
122 ASSERT_TRUE(result.size != 0);
123
124 size_t size = 0;
125 void* buf = flatbuffers_read_size_prefix(result.buf, &size);
126 etdump_ETDump_table_t etdump = etdump_ETDump_as_root_with_identifier(
127 buf, etdump_ETDump_file_identifier);
128
129 etdump_RunData_vec_t run_data_vec = etdump_ETDump_run_data(etdump);
130 ASSERT_EQ(etdump_RunData_vec_len(run_data_vec), 3);
131 ASSERT_EQ(
132 etdump_Event_vec_len(
133 etdump_RunData_events(etdump_RunData_vec_at(run_data_vec, 0))),
134 0);
135
136 if (!etdump_gen[i]->is_static_etdump()) {
137 free(result.buf);
138 }
139 }
140 }
141
TEST_F(ProfilerETDumpTest,AddAllocators)142 TEST_F(ProfilerETDumpTest, AddAllocators) {
143 for (size_t i = 0; i < 2; i++) {
144 etdump_gen[i]->create_event_block("test_block");
145 AllocatorID allocator_id = etdump_gen[i]->track_allocator("test_allocator");
146 EXPECT_EQ(allocator_id, 1);
147 allocator_id = etdump_gen[i]->track_allocator("test_allocator_1");
148 EXPECT_EQ(allocator_id, 2);
149
150 // Add a profiling event and then try to add an allocator which should fail.
151 EventTracerEntry entry = etdump_gen[i]->start_profiling("test_event", 0, 1);
152 etdump_gen[i]->end_profiling(entry);
153 ET_EXPECT_DEATH(etdump_gen[i]->track_allocator("test_allocator"), "");
154 }
155 }
156
TEST_F(ProfilerETDumpTest,AllocationEvents)157 TEST_F(ProfilerETDumpTest, AllocationEvents) {
158 for (size_t i = 0; i < 2; i++) {
159 etdump_gen[i]->create_event_block("test_block");
160
161 // Add allocation events.
162 etdump_gen[i]->track_allocation(1, 64);
163 etdump_gen[i]->track_allocation(2, 128);
164
165 // Add a mix of performance and memory events.
166 etdump_gen[i]->track_allocation(1, 64);
167 EventTracerEntry entry = etdump_gen[i]->start_profiling("test_event", 0, 1);
168 etdump_gen[i]->end_profiling(entry);
169 etdump_gen[i]->track_allocation(2, 128);
170 }
171 }
172
TEST_F(ProfilerETDumpTest,DebugEvent)173 TEST_F(ProfilerETDumpTest, DebugEvent) {
174 for (size_t i = 0; i < 2; i++) {
175 TensorFactory<ScalarType::Float> tf;
176 EValue evalue(tf.ones({3, 2}));
177
178 etdump_gen[i]->create_event_block("test_block");
179
180 void* ptr = malloc(2048);
181 Span<uint8_t> buffer((uint8_t*)ptr, 2048);
182
183 etdump_gen[i]->set_debug_buffer(buffer);
184 etdump_gen[i]->log_evalue(evalue);
185 etdump_gen[i]->log_evalue(evalue, LoggedEValueType::kProgramOutput);
186
187 EValue evalue_int((int64_t)5);
188 etdump_gen[i]->log_evalue(evalue_int);
189
190 EValue evalue_double((double)1.5);
191 etdump_gen[i]->log_evalue(evalue_double);
192
193 EValue evalue_bool(true);
194 etdump_gen[i]->log_evalue(evalue_bool);
195
196 etdump_gen[i]->log_evalue(evalue_bool);
197
198 free(ptr);
199 }
200 }
201
TEST_F(ProfilerETDumpTest,DebugEventTensorList)202 TEST_F(ProfilerETDumpTest, DebugEventTensorList) {
203 for (size_t i = 0; i < 2; i++) {
204 TensorFactory<ScalarType::Int> tf;
205 exec_aten::Tensor storage[2] = {tf.ones({3, 2}), tf.ones({3, 2})};
206 EValue evalue_1(storage[0]);
207 EValue evalue_2(storage[1]);
208 EValue* values_p[2] = {&evalue_1, &evalue_2};
209
210 BoxedEvalueList<exec_aten::Tensor> a_box(values_p, storage, 2);
211 EValue evalue(a_box);
212 evalue.tag = Tag::ListTensor;
213
214 etdump_gen[i]->create_event_block("test_block");
215
216 void* ptr = malloc(2048);
217 Span<uint8_t> buffer((uint8_t*)ptr, 2048);
218
219 etdump_gen[i]->set_debug_buffer(buffer);
220 etdump_gen[i]->log_evalue(evalue);
221
222 free(ptr);
223 }
224 }
225
TEST_F(ProfilerETDumpTest,VerifyLogging)226 TEST_F(ProfilerETDumpTest, VerifyLogging) {
227 TensorFactory<ScalarType::Float> tf;
228 EValue evalue(tf.ones({3, 2}));
229
230 for (size_t i = 0; i < 2; i++) {
231 etdump_gen[i]->create_event_block("test_block");
232
233 void* ptr = malloc(2048);
234 Span<uint8_t> buffer((uint8_t*)ptr, 2048);
235
236 etdump_gen[i]->set_debug_buffer(buffer);
237 etdump_gen[i]->log_evalue(evalue);
238 etdump_gen[i]->log_evalue(evalue, LoggedEValueType::kProgramOutput);
239
240 ETDumpResult result = etdump_gen[i]->get_etdump_data();
241 ASSERT_TRUE(result.buf != nullptr);
242 ASSERT_TRUE(result.size != 0);
243
244 size_t size = 0;
245 void* buf = flatbuffers_read_size_prefix(result.buf, &size);
246 etdump_ETDump_table_t etdump = etdump_ETDump_as_root_with_identifier(
247 buf, etdump_ETDump_file_identifier);
248
249 etdump_RunData_vec_t run_data_vec = etdump_ETDump_run_data(etdump);
250 ASSERT_EQ(etdump_RunData_vec_len(run_data_vec), 1);
251
252 etdump_Event_vec_t events =
253 etdump_RunData_events(etdump_RunData_vec_at(run_data_vec, 0));
254 ASSERT_EQ(etdump_Event_vec_len(events), 2);
255
256 etdump_Event_table_t event = etdump_Event_vec_at(events, 0);
257
258 etdump_DebugEvent_table_t single_debug_event =
259 etdump_Event_debug_event(event);
260 etdump_Value_table_t value =
261 etdump_DebugEvent_debug_entry(single_debug_event);
262 ASSERT_EQ(etdump_Value_tensor_is_present(value), true);
263 ASSERT_EQ(etdump_Value_output_is_present(value), false);
264
265 etdump_Tensor_table_t tensor = etdump_Value_tensor(value);
266 executorch_flatbuffer_ScalarType_enum_t scalar_enum =
267 etdump_Tensor_scalar_type(tensor);
268 ASSERT_EQ(scalar_enum, executorch_flatbuffer_ScalarType_FLOAT);
269 flatbuffers_int64_vec_t sizes = etdump_Tensor_sizes(tensor);
270 ASSERT_EQ(flatbuffers_int64_vec_len(sizes), 2);
271 ASSERT_EQ(flatbuffers_int64_vec_at(sizes, 0), 3);
272 ASSERT_EQ(flatbuffers_int64_vec_at(sizes, 1), 2);
273
274 event = etdump_Event_vec_at(events, 1);
275 single_debug_event = etdump_Event_debug_event(event);
276 value = etdump_DebugEvent_debug_entry(single_debug_event);
277 ASSERT_EQ(etdump_Value_tensor_is_present(value), true);
278 ASSERT_EQ(etdump_Value_output_is_present(value), true);
279 etdump_Bool_table_t bool_val = etdump_Value_output_get(value);
280 bool bool_val_from_table = etdump_Bool_bool_val(bool_val);
281 ASSERT_EQ(bool_val_from_table, true);
282
283 free(ptr);
284 if (!etdump_gen[i]->is_static_etdump()) {
285 free(result.buf);
286 }
287 }
288 }
289
TEST_F(ProfilerETDumpTest,MultipleBlocksWithEvents)290 TEST_F(ProfilerETDumpTest, MultipleBlocksWithEvents) {
291 for (size_t i = 0; i < 2; i++) {
292 etdump_gen[i]->create_event_block("test_block");
293
294 AllocatorID allocator_id_0 =
295 etdump_gen[i]->track_allocator("test_allocator_0");
296 AllocatorID allocator_id_1 =
297 etdump_gen[i]->track_allocator("test_allocator_1");
298 etdump_gen[i]->track_allocation(allocator_id_0, 64);
299 etdump_gen[i]->track_allocation(allocator_id_1, 128);
300
301 EventTracerEntry entry = etdump_gen[i]->start_profiling("test_event", 0, 1);
302 etdump_gen[i]->end_profiling(entry);
303 etdump_gen[i]->create_event_block("test_block_1");
304 allocator_id_0 = etdump_gen[i]->track_allocator("test_allocator_0");
305 allocator_id_1 = etdump_gen[i]->track_allocator("test_allocator_1");
306 etdump_gen[i]->track_allocation(allocator_id_0, 64);
307 etdump_gen[i]->track_allocation(allocator_id_0, 128);
308
309 entry = etdump_gen[i]->start_profiling("test_event", 0, 1);
310 etdump_gen[i]->end_profiling(entry);
311
312 ETDumpResult result = etdump_gen[i]->get_etdump_data();
313 ASSERT_TRUE(result.buf != nullptr);
314 ASSERT_TRUE(result.size != 0);
315
316 size_t size = 0;
317 void* buf = flatbuffers_read_size_prefix(result.buf, &size);
318 etdump_ETDump_table_t etdump = etdump_ETDump_as_root_with_identifier(
319 buf, etdump_ETDump_file_identifier);
320
321 ASSERT_NE(etdump, nullptr);
322 EXPECT_EQ(etdump_ETDump_version(etdump), ETDUMP_VERSION);
323
324 etdump_RunData_vec_t run_data_vec = etdump_ETDump_run_data(etdump);
325 ASSERT_EQ(
326 etdump_gen[i]->get_num_blocks(), etdump_RunData_vec_len(run_data_vec));
327
328 etdump_RunData_table_t run_data_0 = etdump_RunData_vec_at(run_data_vec, 0);
329 EXPECT_EQ(
330 std::string(
331 etdump_RunData_name(run_data_0),
332 strlen(etdump_RunData_name(run_data_0))),
333 "test_block");
334
335 etdump_Allocator_vec_t allocator_vec_0 =
336 etdump_RunData_allocators(run_data_0);
337 ASSERT_EQ(etdump_Allocator_vec_len(allocator_vec_0), 2);
338
339 etdump_Allocator_table_t allocator_0 =
340 etdump_Allocator_vec_at(allocator_vec_0, 0);
341 EXPECT_EQ(
342 std::string(
343 etdump_Allocator_name(allocator_0),
344 strlen(etdump_Allocator_name(allocator_0))),
345 "test_allocator_0");
346
347 etdump_Event_vec_t event_vec = etdump_RunData_events(run_data_0);
348 ASSERT_EQ(etdump_Event_vec_len(event_vec), 3);
349
350 etdump_Event_table_t event_0 = etdump_Event_vec_at(event_vec, 0);
351 EXPECT_EQ(
352 etdump_AllocationEvent_allocation_size(
353 etdump_Event_allocation_event(event_0)),
354 64);
355
356 etdump_Event_table_t event_2 = etdump_Event_vec_at(event_vec, 2);
357 flatbuffers_string_t event_2_name =
358 etdump_ProfileEvent_name(etdump_Event_profile_event(event_2));
359 EXPECT_EQ(std::string(event_2_name, strlen(event_2_name)), "test_event");
360
361 if (!etdump_gen[i]->is_static_etdump()) {
362 free(result.buf);
363 }
364 }
365 }
366
TEST_F(ProfilerETDumpTest,VerifyData)367 TEST_F(ProfilerETDumpTest, VerifyData) {
368 for (size_t i = 0; i < 2; i++) {
369 etdump_gen[i]->create_event_block("test_block");
370
371 etdump_gen[i]->track_allocator("single prof allocator");
372
373 EventTracerEntry entry = etdump_gen[i]->start_profiling("test_event", 0, 1);
374 etdump_gen[i]->end_profiling(entry);
375 entry = etdump_gen[i]->start_profiling("test_event2", 0, 1);
376 etdump_gen[i]->end_profiling(entry);
377
378 ETDumpResult result = etdump_gen[i]->get_etdump_data();
379 ASSERT_TRUE(result.buf != nullptr);
380 ASSERT_TRUE(result.size != 0);
381
382 size_t size = 0;
383 void* buf = flatbuffers_read_size_prefix(result.buf, &size);
384 etdump_ETDump_table_t etdump = etdump_ETDump_as_root_with_identifier(
385 buf, etdump_ETDump_file_identifier);
386
387 ASSERT_NE(etdump, nullptr);
388 EXPECT_EQ(etdump_ETDump_version(etdump), ETDUMP_VERSION);
389
390 etdump_RunData_vec_t run_data_vec = etdump_ETDump_run_data(etdump);
391 EXPECT_EQ(
392 etdump_gen[i]->get_num_blocks(), etdump_RunData_vec_len(run_data_vec));
393
394 etdump_RunData_table_t run_data_single_prof =
395 etdump_RunData_vec_at(run_data_vec, 0);
396 EXPECT_EQ(
397 std::string(
398 etdump_RunData_name(run_data_single_prof),
399 strlen(etdump_RunData_name(run_data_single_prof))),
400 "test_block");
401
402 etdump_Allocator_vec_t allocator_vec =
403 etdump_RunData_allocators(run_data_single_prof);
404
405 etdump_Event_table_t single_event =
406 etdump_Event_vec_at(etdump_RunData_events(run_data_single_prof), 0);
407
408 etdump_ProfileEvent_table_t single_prof_event =
409 etdump_Event_profile_event(single_event);
410
411 EXPECT_EQ(
412 std::string(
413 etdump_ProfileEvent_name(single_prof_event),
414 strlen(etdump_ProfileEvent_name(single_prof_event))),
415 "test_event");
416 EXPECT_EQ(etdump_ProfileEvent_chain_index(single_prof_event), 0);
417
418 flatbuffers_string_t allocator_name =
419 etdump_Allocator_name(etdump_Allocator_vec_at(allocator_vec, 0));
420 EXPECT_EQ(
421 std::string(allocator_name, strlen(allocator_name)),
422 "single prof allocator");
423
424 if (!etdump_gen[i]->is_static_etdump()) {
425 free(result.buf);
426 }
427 }
428 }
429
TEST_F(ProfilerETDumpTest,LogDelegateIntermediateOutput)430 TEST_F(ProfilerETDumpTest, LogDelegateIntermediateOutput) {
431 for (size_t i = 0; i < 2; i++) {
432 void* ptr = malloc(2048);
433 Span<uint8_t> buffer((uint8_t*)ptr, 2048);
434
435 etdump_gen[i]->create_event_block("test_block");
436 TensorFactory<ScalarType::Float> tf;
437
438 ET_EXPECT_DEATH(
439 etdump_gen[i]->log_intermediate_output_delegate(
440 "test_event_tensor",
441 static_cast<torch::executor::DebugHandle>(-1),
442 tf.ones({3, 2})),
443 "Must pre-set debug buffer with set_debug_buffer()");
444 etdump_gen[i]->set_debug_buffer(buffer);
445
446 // Log a tensor
447 etdump_gen[i]->log_intermediate_output_delegate(
448 "test_event_tensor",
449 static_cast<torch::executor::DebugHandle>(-1),
450 tf.ones({3, 2}));
451
452 // Log a tensor list
453 std::vector<Tensor> tensors = {tf.ones({5, 4}), tf.ones({7, 6})};
454 etdump_gen[i]->log_intermediate_output_delegate(
455 "test_event_tensorlist",
456 static_cast<torch::executor::DebugHandle>(-1),
457 ArrayRef<Tensor>(tensors.data(), tensors.size()));
458
459 // Log an int
460 etdump_gen[i]->log_intermediate_output_delegate(
461 "test_event_tensorlist",
462 static_cast<torch::executor::DebugHandle>(-1),
463 10);
464
465 // Log a double
466 etdump_gen[i]->log_intermediate_output_delegate(
467 "test_event_tensorlist",
468 static_cast<torch::executor::DebugHandle>(-1),
469 20.75);
470
471 // Log a bool
472 etdump_gen[i]->log_intermediate_output_delegate(
473 "test_event_tensorlist",
474 static_cast<torch::executor::DebugHandle>(-1),
475 true);
476
477 ETDumpResult result = etdump_gen[i]->get_etdump_data();
478 ASSERT_TRUE(result.buf != nullptr);
479 ASSERT_TRUE(result.size != 0);
480
481 free(ptr);
482 if (!etdump_gen[i]->is_static_etdump()) {
483 free(result.buf);
484 }
485 }
486 }
487
TEST_F(ProfilerETDumpTest,VerifyDelegateIntermediateLogging)488 TEST_F(ProfilerETDumpTest, VerifyDelegateIntermediateLogging) {
489 TensorFactory<ScalarType::Float> tf;
490 EValue evalue(tf.ones({3, 2}));
491
492 for (size_t i = 0; i < 2; i++) {
493 etdump_gen[i]->create_event_block("test_block");
494
495 void* ptr = malloc(2048);
496 Span<uint8_t> buffer((uint8_t*)ptr, 2048);
497
498 etdump_gen[i]->set_debug_buffer(buffer);
499
500 // Event 0
501 etdump_gen[i]->log_intermediate_output_delegate(
502 nullptr, 257, tf.ones({3, 4}));
503 // Event 1
504 etdump_gen[i]->log_intermediate_output_delegate(
505 nullptr, 258, tf.ones({5, 6}));
506
507 ETDumpResult result = etdump_gen[i]->get_etdump_data();
508 ASSERT_TRUE(result.buf != nullptr);
509 ASSERT_TRUE(result.size != 0);
510
511 size_t size = 0;
512 void* buf = flatbuffers_read_size_prefix(result.buf, &size);
513 etdump_ETDump_table_t etdump = etdump_ETDump_as_root_with_identifier(
514 buf, etdump_ETDump_file_identifier);
515
516 etdump_RunData_vec_t run_data_vec = etdump_ETDump_run_data(etdump);
517 ASSERT_EQ(etdump_RunData_vec_len(run_data_vec), 1);
518
519 etdump_Event_vec_t events =
520 etdump_RunData_events(etdump_RunData_vec_at(run_data_vec, 0));
521 ASSERT_EQ(etdump_Event_vec_len(events), 2);
522
523 // Verify Event 0
524 etdump_Event_table_t event_0 = etdump_Event_vec_at(events, 0);
525
526 etdump_DebugEvent_table_t single_debug_event =
527 etdump_Event_debug_event(event_0);
528 etdump_Value_table_t value =
529 etdump_DebugEvent_debug_entry(single_debug_event);
530 ASSERT_EQ(etdump_Value_tensor_is_present(value), true);
531
532 etdump_Tensor_table_t tensor = etdump_Value_tensor(value);
533 executorch_flatbuffer_ScalarType_enum_t scalar_enum =
534 etdump_Tensor_scalar_type(tensor);
535 ASSERT_EQ(scalar_enum, executorch_flatbuffer_ScalarType_FLOAT);
536 flatbuffers_int64_vec_t sizes = etdump_Tensor_sizes(tensor);
537 ASSERT_EQ(flatbuffers_int64_vec_len(sizes), 2);
538 ASSERT_EQ(flatbuffers_int64_vec_at(sizes, 0), 3);
539 ASSERT_EQ(flatbuffers_int64_vec_at(sizes, 1), 4);
540
541 // Verify Event 1
542 etdump_Event_table_t event_1 = etdump_Event_vec_at(events, 1);
543
544 single_debug_event = etdump_Event_debug_event(event_1);
545 value = etdump_DebugEvent_debug_entry(single_debug_event);
546
547 tensor = etdump_Value_tensor(value);
548 sizes = etdump_Tensor_sizes(tensor);
549 ASSERT_EQ(flatbuffers_int64_vec_len(sizes), 2);
550 ASSERT_EQ(flatbuffers_int64_vec_at(sizes, 0), 5);
551 ASSERT_EQ(flatbuffers_int64_vec_at(sizes, 1), 6);
552
553 // Event 1 should have a empty delegate_debug_id_str
554 flatbuffers_string_t delegate_debug_id_name =
555 etdump_DebugEvent_delegate_debug_id_str(
556 etdump_Event_debug_event(event_1));
557
558 EXPECT_EQ(delegate_debug_id_name, nullptr);
559 // Check for the correct delegate_debug_id_int
560 EXPECT_EQ(
561 etdump_DebugEvent_delegate_debug_id_int(
562 etdump_Event_debug_event(event_1)),
563 258);
564
565 free(ptr);
566 if (!etdump_gen[i]->is_static_etdump()) {
567 free(result.buf);
568 }
569 }
570 }
571
TEST_F(ProfilerETDumpTest,LogDelegateEvents)572 TEST_F(ProfilerETDumpTest, LogDelegateEvents) {
573 for (size_t i = 0; i < 2; i++) {
574 etdump_gen[i]->create_event_block("test_block");
575
576 // Event 0
577 etdump_gen[i]->log_profiling_delegate(nullptr, 276, 1, 2, nullptr, 0);
578 // Event 1
579 const char* metadata = "test_metadata";
580 etdump_gen[i]->log_profiling_delegate(
581 nullptr, 278, 1, 2, metadata, strlen(metadata) + 1);
582 EventTracerEntry entry = etdump_gen[i]->start_profiling_delegate(
583 "test_event", static_cast<torch::executor::DebugHandle>(-1));
584 EXPECT_NE(entry.delegate_event_id_type, DelegateDebugIdType::kNone);
585 // Event 2
586 etdump_gen[i]->end_profiling_delegate(
587 entry, metadata, strlen(metadata) + 1);
588 // Event 3
589 etdump_gen[i]->log_profiling_delegate(
590 "test_event",
591 static_cast<torch::executor::DebugHandle>(-1),
592 1,
593 2,
594 nullptr,
595 0);
596 // Event 4
597 etdump_gen[i]->log_profiling_delegate(
598 "test_event",
599 static_cast<torch::executor::DebugHandle>(-1),
600 1,
601 2,
602 metadata,
603 strlen(metadata) + 1);
604
605 // Only a valid name or delegate debug index should be passed in. If valid
606 // entries are passed in for both then the test should assert out.
607 ET_EXPECT_DEATH(
608 etdump_gen[i]->start_profiling_delegate("test_event", 1),
609 "Only name or delegate_debug_index can be valid. Check DelegateMappingBuilder documentation for more details.");
610 ET_EXPECT_DEATH(
611 etdump_gen[i]->log_profiling_delegate(
612 "test_event", 1, 1, 2, nullptr, 0),
613 "Only name or delegate_debug_index can be valid. Check DelegateMappingBuilder documentation for more details.");
614 ET_EXPECT_DEATH(
615 etdump_gen[i]->end_profiling(entry),
616 "Delegate events must use end_profiling_delegate to mark the end of a delegate profiling event.");
617
618 ETDumpResult result = etdump_gen[i]->get_etdump_data();
619 ASSERT_TRUE(result.buf != nullptr);
620 ASSERT_TRUE(result.size != 0);
621
622 // Run verification tests on the data that was just serialized.
623 size_t size = 0;
624 void* buf = flatbuffers_read_size_prefix(result.buf, &size);
625 etdump_ETDump_table_t etdump = etdump_ETDump_as_root_with_identifier(
626 buf, etdump_ETDump_file_identifier);
627 etdump_RunData_vec_t run_data_vec = etdump_ETDump_run_data(etdump);
628
629 // Event 0
630 etdump_RunData_table_t run_data_0 = etdump_RunData_vec_at(run_data_vec, 0);
631 etdump_Event_vec_t event_vec = etdump_RunData_events(run_data_0);
632 ASSERT_EQ(etdump_Event_vec_len(event_vec), 5);
633 etdump_Event_table_t event = etdump_Event_vec_at(event_vec, 0);
634
635 flatbuffers_string_t delegate_debug_id_name =
636 etdump_ProfileEvent_delegate_debug_id_str(
637 etdump_Event_profile_event(event));
638
639 // Event 0 should have a empty delegate_debug_id_str
640 EXPECT_EQ(delegate_debug_id_name, nullptr);
641 // Check for the correct delegate_debug_id_int
642 EXPECT_EQ(
643 etdump_ProfileEvent_delegate_debug_id_int(
644 etdump_Event_profile_event(event)),
645 276);
646 flatbuffers_uint8_vec_t debug_metadata_name =
647 etdump_ProfileEvent_delegate_debug_metadata(
648 etdump_Event_profile_event(event));
649 // Event 0 should have an empty delegate_debug_metadata string.
650 EXPECT_EQ(flatbuffers_uint8_vec_len(debug_metadata_name), 0);
651
652 // Event 1
653 event = etdump_Event_vec_at(event_vec, 1);
654 // Check for the correct delegate_debug_id_int
655 EXPECT_EQ(
656 etdump_ProfileEvent_delegate_debug_id_int(
657 etdump_Event_profile_event(event)),
658 278);
659 debug_metadata_name = etdump_ProfileEvent_delegate_debug_metadata(
660 etdump_Event_profile_event(event));
661 // Check for the correct delegate_debug_metadata string
662 EXPECT_EQ(
663 std::string(
664 (char*)debug_metadata_name,
665 flatbuffers_uint8_vec_len(debug_metadata_name) - 1),
666 "test_metadata");
667
668 // Event 2
669 event = etdump_Event_vec_at(event_vec, 2);
670 delegate_debug_id_name = etdump_ProfileEvent_delegate_debug_id_str(
671 etdump_Event_profile_event(event));
672 // Check for the correct delegate_debug_id_str string.
673 EXPECT_EQ(
674 std::string(delegate_debug_id_name, strlen(delegate_debug_id_name)),
675 "test_event");
676 // Event 2 used a string delegate debug identifier, so delegate_debug_id_int
677 // should be -1.
678 EXPECT_EQ(
679 etdump_ProfileEvent_delegate_debug_id_int(
680 etdump_Event_profile_event(event)),
681 -1);
682 if (!etdump_gen[i]->is_static_etdump()) {
683 free(result.buf);
684 }
685 }
686 }
687
TEST_F(ProfilerETDumpTest,WriteAfterGetETDumpData)688 TEST_F(ProfilerETDumpTest, WriteAfterGetETDumpData) {
689 for (size_t i = 0; i < 2; i++) {
690 for (size_t j = 0; j < 2; j++) {
691 etdump_gen[i]->create_event_block("test_block");
692 EventTracerEntry entry =
693 etdump_gen[i]->start_profiling("test_event", 0, 1);
694 etdump_gen[i]->end_profiling(entry);
695
696 ETDumpResult result = etdump_gen[i]->get_etdump_data();
697 ASSERT_TRUE(result.buf != nullptr);
698 ASSERT_TRUE(result.size != 0);
699
700 size_t size = 0;
701 void* buf = flatbuffers_read_size_prefix(result.buf, &size);
702 etdump_ETDump_table_t etdump = etdump_ETDump_as_root_with_identifier(
703 buf, etdump_ETDump_file_identifier);
704
705 ASSERT_NE(etdump, nullptr);
706 EXPECT_EQ(etdump_ETDump_version(etdump), ETDUMP_VERSION);
707
708 etdump_RunData_vec_t run_data_vec = etdump_ETDump_run_data(etdump);
709 EXPECT_EQ(
710 etdump_gen[i]->get_num_blocks(),
711 etdump_RunData_vec_len(run_data_vec));
712
713 etdump_RunData_table_t run_data_single_prof =
714 etdump_RunData_vec_at(run_data_vec, 0);
715 EXPECT_EQ(
716 std::string(
717 etdump_RunData_name(run_data_single_prof),
718 strlen(etdump_RunData_name(run_data_single_prof))),
719 "test_block");
720
721 if (!etdump_gen[i]->is_static_etdump()) {
722 free(result.buf);
723 }
724 }
725 }
726 }
727