Host trap PC sampling uses new record type (#1207)

* Host trap PC sampling uses new record type

* removing redundant field

* formatting

* simplifying templates in the parser - no need for HostTrap boolean

* reviving some parser tests

* hw_id decoding on GFX9

* HW id parser test

* parser CID test

* Parser multigpu test

* removing rocprofiler_pc_sampling_record_t and some fields from hw_id

* simplifying parser context

* keep bench test internally

* initializing gfx9_hw_id_t differently

* anonymous struct first

* avoiding inlining initialization of struct
Tento commit je obsažen v:
Vladimir Indic
2024-11-20 21:02:47 +01:00
odevzdal GitHub
rodič 55aea3ef10
revize bc52c17e64
21 změnil soubory, kde provedl 1319 přidání a 738 odebrání
+102 -65
Zobrazit soubor
@@ -46,19 +46,20 @@ public:
/**
* Sample user memory allocation callback.
* It expects userdata to be cast-able to a pointer to
* std::vector<std::pair<rocprofiler_pc_sampling_record_t*, uint64_t>>
* std::vector<std::pair<PcSamplingRecordT*, uint64_t>>
*/
template <typename PcSamplingRecordT>
static uint64_t
alloc_callback(rocprofiler_pc_sampling_record_t** buffer, uint64_t size, void* userdata)
alloc_callback(PcSamplingRecordT** buffer, uint64_t size, void* userdata)
{
*buffer = new rocprofiler_pc_sampling_record_t[size];
*buffer = new PcSamplingRecordT[size];
auto& vector =
*reinterpret_cast<std::vector<std::pair<rocprofiler_pc_sampling_record_t*, uint64_t>>*>(
userdata);
*reinterpret_cast<std::vector<std::pair<PcSamplingRecordT*, uint64_t>>*>(userdata);
vector.push_back({*buffer, size});
return size;
}
template <typename PcSamplingRecordT>
void
multithread_queue_hammer(size_t tid, Latch* latch)
{
@@ -70,10 +71,11 @@ multithread_queue_hammer(size_t tid, Latch* latch)
constexpr int NUM_QUEUES = MockDoorBell::num_unique_bells / NUM_THREADS;
constexpr int ACTION_MAX = QSIZE * NUM_QUEUES / 2;
std::shared_ptr<MockRuntimeBuffer> buffer = std::make_shared<MockRuntimeBuffer>(tid);
auto buffer = std::make_shared<MockRuntimeBuffer<PcSamplingRecordT>>(tid);
std::array<std::shared_ptr<MockQueue>, NUM_QUEUES> queues;
std::array<std::vector<std::shared_ptr<MockDispatch>>, NUM_QUEUES> active_dispatches;
std::array<std::shared_ptr<MockQueue<PcSamplingRecordT>>, NUM_QUEUES> queues;
std::array<std::vector<std::shared_ptr<MockDispatch<PcSamplingRecordT>>>, NUM_QUEUES>
active_dispatches;
int num_reset_queues = 0;
int num_samples_generated = 0;
@@ -82,9 +84,10 @@ multithread_queue_hammer(size_t tid, Latch* latch)
size_t max_q_occupancy = 0;
for(int i = 0; i < NUM_QUEUES; i++)
queues[i] = std::make_shared<MockQueue>(QSIZE, buffer);
queues[i] = std::make_shared<MockQueue<PcSamplingRecordT>>(QSIZE, buffer);
for(int i = 0; i < NUM_QUEUES; i++)
active_dispatches[i].push_back(std::make_shared<MockDispatch>(queues[i]));
active_dispatches[i].push_back(
std::make_shared<MockDispatch<PcSamplingRecordT>>(queues[i]));
for(int i = 0; i < NUM_ACTIONS; i++)
{
@@ -95,7 +98,7 @@ multithread_queue_hammer(size_t tid, Latch* latch)
// Delete queue and create new one
active_dispatches[q] = {};
queues[q].reset();
queues[q] = std::make_shared<MockQueue>(QSIZE, buffer);
queues[q] = std::make_shared<MockQueue<PcSamplingRecordT>>(QSIZE, buffer);
num_reset_queues++;
}
else if(action > ACTION_MAX / 2 && active_dispatches[q].size() > 1)
@@ -108,7 +111,8 @@ multithread_queue_hammer(size_t tid, Latch* latch)
// Add new dispatch
if(active_dispatches[q].size() < QSIZE)
{
active_dispatches[q].push_back(std::make_shared<MockDispatch>(queues[q]));
active_dispatches[q].push_back(
std::make_shared<MockDispatch<PcSamplingRecordT>>(queues[q]));
num_dispatches_generated += 1;
}
@@ -117,7 +121,8 @@ multithread_queue_hammer(size_t tid, Latch* latch)
for(auto& queue : active_dispatches)
{
EXPECT_NE(queue.size(), 0);
std::shared_ptr<MockDispatch> rand_dispatch = queue[rdgen() % queue.size()];
std::shared_ptr<MockDispatch<PcSamplingRecordT>> rand_dispatch =
queue[rdgen() % queue.size()];
MockWave(rand_dispatch).genPCSample();
num_samples_generated += 1;
avg_q_occupancy += queue.size();
@@ -127,23 +132,23 @@ multithread_queue_hammer(size_t tid, Latch* latch)
latch->sync();
std::vector<std::pair<rocprofiler_pc_sampling_record_t*, uint64_t>> all_allocations;
std::vector<std::pair<PcSamplingRecordT*, uint64_t>> all_allocations;
CHECK_PARSER(_parse_buffer<GFX9>((generic_sample_t*) buffer->packets.data(),
buffer->packets.size(),
alloc_callback,
alloc_callback<PcSamplingRecordT>,
(void*) &all_allocations,
&corr_map));
EXPECT_EQ(all_allocations.size(), NUM_ACTIONS); // Incorrect number of callbacks
for(auto sb = 0ul; sb < all_allocations.size(); sb++)
{
rocprofiler_pc_sampling_record_t* samples = all_allocations[sb].first;
size_t num_samples = all_allocations[sb].second;
PcSamplingRecordT* samples = all_allocations[sb].first;
size_t num_samples = all_allocations[sb].second;
EXPECT_EQ(num_samples, NUM_QUEUES);
for(size_t i = 0; i < num_samples; i++)
EXPECT_EQ(samples[i].correlation_id.internal, samples[i].pc.loaded_code_object_offset);
EXPECT_EQ(samples[i].correlation_id.internal, samples[i].pc.code_object_offset);
delete[] samples;
}
}
@@ -152,6 +157,7 @@ multithread_queue_hammer(size_t tid, Latch* latch)
* Benchmarks how fast the parser can process samples on a single threaded case
* Current: 5600X with -Ofast, up to >140 million samples/s or ~9GB/s R/W (18GB/s bidirectional)
*/
template <typename PcSamplingRecordT>
static std::pair<size_t, size_t>
MultiThread_BenchMark(size_t tid, Latch* latch)
{
@@ -161,14 +167,16 @@ MultiThread_BenchMark(size_t tid, Latch* latch)
constexpr size_t DISP_PER_QUEUE = 16;
constexpr size_t NUM_QUEUES = 1;
std::shared_ptr<MockRuntimeBuffer> buffer = std::make_shared<MockRuntimeBuffer>(tid);
std::array<std::vector<std::shared_ptr<MockDispatch>>, NUM_QUEUES> active_dispatches;
auto buffer = std::make_shared<MockRuntimeBuffer<PcSamplingRecordT>>(tid);
std::array<std::vector<std::shared_ptr<MockDispatch<PcSamplingRecordT>>>, NUM_QUEUES>
active_dispatches;
for(size_t q = 0; q < NUM_QUEUES; q++)
{
std::shared_ptr<MockQueue> queue = std::make_shared<MockQueue>(DISP_PER_QUEUE * 2, buffer);
auto queue = std::make_shared<MockQueue<PcSamplingRecordT>>(DISP_PER_QUEUE * 2, buffer);
for(size_t d = 0; d < DISP_PER_QUEUE; d++)
active_dispatches[q].push_back(std::make_shared<MockDispatch>(queue));
active_dispatches[q].push_back(
std::make_shared<MockDispatch<PcSamplingRecordT>>(queue));
}
constexpr size_t TOTAL_NUM_SAMPLES = NUM_QUEUES * DISP_PER_QUEUE * SAMPLE_PER_DISPATCH;
@@ -179,29 +187,31 @@ MultiThread_BenchMark(size_t tid, Latch* latch)
for(size_t i = 0; i < SAMPLE_PER_DISPATCH; i++)
MockWave(dispatch).genPCSample();
std::pair<rocprofiler_pc_sampling_record_t*, size_t> userdata;
userdata.first = new rocprofiler_pc_sampling_record_t[TOTAL_NUM_SAMPLES];
std::pair<PcSamplingRecordT*, size_t> userdata;
userdata.first = new PcSamplingRecordT[TOTAL_NUM_SAMPLES];
userdata.second = TOTAL_NUM_SAMPLES;
latch->sync();
auto t0 = std::chrono::system_clock::now();
CHECK_PARSER(_parse_buffer<GFX9>(
(generic_sample_t*) buffer->packets.data(),
buffer->packets.size(),
[](rocprofiler_pc_sampling_record_t** sample, uint64_t size, void* userdata_) {
auto* pair =
reinterpret_cast<std::pair<rocprofiler_pc_sampling_record_t*, size_t>*>(userdata_);
*sample = pair->first;
user_callback_t<PcSamplingRecordT> user_cb =
[](PcSamplingRecordT** sample, uint64_t size, void* userdata_) {
auto* pair = reinterpret_cast<std::pair<PcSamplingRecordT*, size_t>*>(userdata_);
*sample = pair->first;
return size;
},
&userdata,
&corr_map));
};
auto t0 = std::chrono::system_clock::now();
CHECK_PARSER(_parse_buffer<GFX9>((generic_sample_t*) buffer->packets.data(),
buffer->packets.size(),
user_cb,
&userdata,
&corr_map));
auto t1 = std::chrono::system_clock::now();
delete[] userdata.first;
return {TOTAL_NUM_SAMPLES, (t1 - t0).count()};
}
template <typename PcSamplingRecordT>
void
multithread_codeobj(size_t tid, Latch* latch)
{
@@ -215,11 +225,11 @@ multithread_codeobj(size_t tid, Latch* latch)
constexpr int NUM_SAMPLES = 50;
constexpr int QSIZE = 16;
auto buffer = std::make_shared<MockRuntimeBuffer>(tid);
auto queue = std::make_shared<MockQueue>(QSIZE, buffer);
auto buffer = std::make_shared<MockRuntimeBuffer<PcSamplingRecordT>>(tid);
auto queue = std::make_shared<MockQueue<PcSamplingRecordT>>(QSIZE, buffer);
std::pair<rocprofiler_pc_sampling_record_t*, size_t> userdata;
userdata.first = new rocprofiler_pc_sampling_record_t[NUM_SAMPLES];
std::pair<PcSamplingRecordT*, size_t> userdata;
userdata.first = new PcSamplingRecordT[NUM_SAMPLES];
userdata.second = NUM_SAMPLES;
latch->sync();
@@ -227,7 +237,7 @@ multithread_codeobj(size_t tid, Latch* latch)
for(int d = 0; d < NUM_DISPATCH; d++)
{
buffer->packets.clear();
auto dispatch = std::make_shared<MockDispatch>(queue);
auto dispatch = std::make_shared<MockDispatch<PcSamplingRecordT>>(queue);
const size_t pc_base_addr = NUM_SAMPLES * dispatch->unique_id;
table->insert(addr_range_t{pc_base_addr, NUM_SAMPLES, dispatch->unique_id});
@@ -242,25 +252,25 @@ multithread_codeobj(size_t tid, Latch* latch)
dispatch->submit(uni);
}
CHECK_PARSER(_parse_buffer<GFX9>(
(generic_sample_t*) buffer->packets.data(),
buffer->packets.size(),
[](rocprofiler_pc_sampling_record_t** sample, uint64_t size, void* userdata_) {
auto* pair =
reinterpret_cast<std::pair<rocprofiler_pc_sampling_record_t*, size_t>*>(
userdata_);
*sample = pair->first;
user_callback_t<PcSamplingRecordT> user_cb =
[](PcSamplingRecordT** sample, uint64_t size, void* userdata_) {
auto* pair = reinterpret_cast<std::pair<PcSamplingRecordT*, size_t>*>(userdata_);
*sample = pair->first;
assert(size <= NUM_SAMPLES);
return size;
},
&userdata,
&corr_map));
};
CHECK_PARSER(_parse_buffer<GFX9>((generic_sample_t*) buffer->packets.data(),
buffer->packets.size(),
user_cb,
&userdata,
&corr_map));
for(int s = 0; s < NUM_SAMPLES; s++)
{
const auto& pc = userdata.first[s].pc;
EXPECT_EQ(pc.loaded_code_object_id, dispatch->unique_id);
EXPECT_EQ(pc.loaded_code_object_offset, s);
EXPECT_EQ(pc.code_object_id, dispatch->unique_id);
EXPECT_EQ(pc.code_object_offset, s);
}
table->remove(addr_range_t{pc_base_addr, NUM_SAMPLES, dispatch->unique_id});
@@ -269,7 +279,9 @@ multithread_codeobj(size_t tid, Latch* latch)
delete[] userdata.first;
}
TEST(pcs_parser, bench_test)
template <typename PcSamplingRecordT>
void
pcs_parser_bench_test()
{
size_t time = 0;
size_t samples = 0;
@@ -280,7 +292,8 @@ TEST(pcs_parser, bench_test)
std::vector<std::future<std::pair<size_t, size_t>>> threads{};
for(size_t t = 0; t < NUM_THREADS; t++)
threads.push_back(std::async(std::launch::async, MultiThread_BenchMark, t, &latch));
threads.push_back(std::async(
std::launch::async, MultiThread_BenchMark<PcSamplingRecordT>, t, &latch));
if(it == 0) continue; // Skip warmup
@@ -295,23 +308,47 @@ TEST(pcs_parser, bench_test)
double mean = 1E3 * NUM_THREADS * samples / time;
std::cout << "Benchmark: Parsed " << int(mean * 1E3 + 0.5) * 1E-3f << " Msample/s (";
std::cout << int(sizeof(rocprofiler_pc_sampling_record_t) * mean) << " MB/s)" << std::endl;
std::cout << int(sizeof(PcSamplingRecordT) * mean) << " MB/s)" << std::endl;
};
TEST(pcs_parser, bench_test)
{
pcs_parser_bench_test<rocprofiler_pc_sampling_record_host_trap_v0_t>();
pcs_parser_bench_test<rocprofiler_pc_sampling_record_stochastic_v0_t>();
}
template <typename PcSamplingRecordT>
void
pcs_parser_hammer_test()
{
Latch latch(NUM_THREADS);
std::vector<std::future<void>> threads{};
for(size_t i = 0; i < NUM_THREADS; i++)
threads.push_back(
std::async(std::launch::async, multithread_queue_hammer<PcSamplingRecordT>, i, &latch));
};
TEST(pcs_parser, hammer_test)
{
Latch latch(NUM_THREADS);
pcs_parser_hammer_test<rocprofiler_pc_sampling_record_host_trap_v0_t>();
pcs_parser_hammer_test<rocprofiler_pc_sampling_record_stochastic_v0_t>();
}
std::vector<std::future<void>> threads{};
for(size_t i = 0; i < NUM_THREADS; i++)
threads.push_back(std::async(std::launch::async, multithread_queue_hammer, i, &latch));
};
TEST(pcs_parser, codeobj_test)
template <typename PcSamplingRecordT>
void
pcs_parser_codeobj_test()
{
Latch latch(NUM_THREADS);
std::vector<std::future<void>> threads{};
for(size_t i = 0; i < NUM_THREADS; i++)
threads.push_back(std::async(std::launch::async, multithread_codeobj, i, &latch));
};
threads.push_back(
std::async(std::launch::async, multithread_codeobj<PcSamplingRecordT>, i, &latch));
}
TEST(pcs_parser, codeobj_test)
{
pcs_parser_codeobj_test<rocprofiler_pc_sampling_record_host_trap_v0_t>();
pcs_parser_codeobj_test<rocprofiler_pc_sampling_record_stochastic_v0_t>();
}