Adding rocprofilerv2
Change-Id: Ic0cc280ba207d2b8f6ccae1cd4ac3184152fc1ad
[ROCm/rocprofiler commit: 8032adb64f]
Bu işleme şunda yer alıyor:
@@ -0,0 +1,32 @@
|
||||
/* Copyright (c) 2022 Advanced Micro Devices, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE. */
|
||||
|
||||
__kernel void copyA(__global unsigned int* a, __global unsigned int* b) {
|
||||
uint tid = get_global_id(0);
|
||||
a[tid] = b[tid];
|
||||
}
|
||||
__kernel void copyB(__global unsigned int* a, __global unsigned int* b) {
|
||||
uint tid = get_global_id(0);
|
||||
a[tid] = b[tid];
|
||||
}
|
||||
__kernel void copyC(__global unsigned int* a, __global unsigned int* b) {
|
||||
uint tid = get_global_id(0);
|
||||
a[tid] = b[tid];
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/** \mainpage ROC Profiler Multi Process Binary Test
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test is to test ROC profiler as a binary against a
|
||||
* multiprocess application.Test application launches an empty kernel
|
||||
* on multiple threads from both parent and child process.
|
||||
*
|
||||
* The test then parses the csv and verifies if the nuber of context collected
|
||||
* are equal to number of threads launched in test application.
|
||||
*
|
||||
* Test also does some basic verification if counter values are non-negative
|
||||
*/
|
||||
|
||||
#include <hip/hip_runtime.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
// empty kernel
|
||||
__global__ void kernel() {}
|
||||
|
||||
void KernelLaunch() {
|
||||
// run empty kernel
|
||||
kernel<<<1, 1>>>();
|
||||
hipDeviceSynchronize();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// create as many threads as number of cores in system
|
||||
int num_cpu_cores = GetNumberOfCores();
|
||||
|
||||
pid_t childpid = fork();
|
||||
|
||||
if (childpid > 0) { // Parent
|
||||
// create a pool of thrads
|
||||
std::vector<std::thread> threads(num_cpu_cores);
|
||||
for (int n = 0; n < num_cpu_cores / 2; ++n) {
|
||||
threads[n] = std::thread(KernelLaunch);
|
||||
}
|
||||
|
||||
for (int n = 0; n < num_cpu_cores / 2; ++n) {
|
||||
threads[n].join();
|
||||
}
|
||||
// wait for child exit
|
||||
wait(NULL);
|
||||
|
||||
} else if (!childpid) { // child
|
||||
// create a pool of thrads
|
||||
std::vector<std::thread> threads(num_cpu_cores);
|
||||
for (int n = 0; n < num_cpu_cores / 2; ++n) {
|
||||
threads[n] = std::thread(KernelLaunch);
|
||||
}
|
||||
|
||||
for (int n = 0; n < num_cpu_cores / 2; ++n) {
|
||||
threads[n].join();
|
||||
}
|
||||
} else { // failure
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/** \mainpage ROC Profiler Binary Test
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test is to test ROC profiler as a binary against a
|
||||
* multithreaded application.Test application launches an empty kernel
|
||||
* on multiple threads.
|
||||
*
|
||||
* The test then parses the csv and verifies if the nuber of kernel dispatches
|
||||
* are equal to number of threads launched in test application.
|
||||
*
|
||||
* Test also does some basic verification if counter values are non-negative
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#include "utils/csv_parser.h"
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
// Multi Queue kernel dispatch count test
|
||||
int QueueDependencyTest(std::string profiler_output) {
|
||||
CSVParser parser;
|
||||
parser.ParseCSV(profiler_output);
|
||||
countermap counter_map = parser.GetCounterMap();
|
||||
|
||||
// number of kernel dispatches in test
|
||||
uint32_t dispatch_count = 3;
|
||||
|
||||
uint32_t dispatch_counter = 0;
|
||||
for (size_t i = 0; i < counter_map.size(); i++) {
|
||||
std::string* dispatch_id = parser.ReadCounter(i, 1);
|
||||
if (dispatch_id != nullptr) {
|
||||
if (dispatch_id->find("dispatch") != std::string::npos) {
|
||||
dispatch_counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dispatch count test: Number of dispatches must be equal to
|
||||
// number of kernel launches in test_app
|
||||
if (dispatch_counter == dispatch_count) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string ReadProfilerBuffer(const char* cmd) {
|
||||
std::vector<char> buffer(1028);
|
||||
std::string profiler_output;
|
||||
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
|
||||
if (!pipe) {
|
||||
throw std::runtime_error("popen() failed!");
|
||||
}
|
||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
||||
profiler_output += buffer.data();
|
||||
}
|
||||
return profiler_output;
|
||||
}
|
||||
|
||||
std::string InitMultiQueueTest() {
|
||||
std::string input_app_path = GetRunningPath("profiler_multiqueue_test");
|
||||
std::stringstream input_txt_path;
|
||||
input_txt_path << input_app_path << "gtests/apps/goldentraces/input.txt";
|
||||
std::string rocprofv2_path =
|
||||
GetRunningPath("build/tests/featuretests/profiler/profiler_multiqueue_test");
|
||||
std::stringstream command(rocprofv2_path);
|
||||
|
||||
command << "./rocprofv2 -i " << input_txt_path.str().c_str() << " " << input_app_path
|
||||
<< "multiqueue_testapp";
|
||||
|
||||
std::string result = ReadProfilerBuffer(command.str().c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int test_status = -1;
|
||||
std::string profiler_output;
|
||||
|
||||
// initialize multi queue dependecy test
|
||||
profiler_output = InitMultiQueueTest();
|
||||
|
||||
// multi queue dispatch count test
|
||||
test_status = QueueDependencyTest(profiler_output);
|
||||
|
||||
return test_status;
|
||||
}
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/** \mainpage ROC Profiler Multi Queue Dependency Test
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test is to ensure ROC profiler does not go to deadlock
|
||||
* when multiple queue are created and they are dependent on each other
|
||||
*
|
||||
*/
|
||||
|
||||
#include "discretetests/binary/multiqueue_testapp.h"
|
||||
|
||||
#include "src/utils/exception.h"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
std::vector<hsa_agent_t> Device::all_devices;
|
||||
|
||||
int main() {
|
||||
hsa_status_t status;
|
||||
MQDependencyTest obj;
|
||||
|
||||
// Get Agent info
|
||||
obj.DeviceDiscovery();
|
||||
|
||||
char agent_name[64];
|
||||
status = hsa_agent_get_info(gpu[0].agent, HSA_AGENT_INFO_NAME, agent_name);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
// Getting Current Path
|
||||
std::string current_path = fs::current_path().generic_string();
|
||||
// Getting hasco Path
|
||||
std::string ko_path = current_path + "/featuretests/profiler/" +
|
||||
std::string(agent_name) + "_copy.hsaco";
|
||||
|
||||
MQDependencyTest::CodeObject code_object;
|
||||
if (!obj.LoadCodeObject(ko_path, gpu[0].agent, code_object)) {
|
||||
printf("Kernel file not found or not usable with given agent.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
MQDependencyTest::Kernel copyA;
|
||||
if (!obj.GetKernel(code_object, "copyA", gpu[0].agent, copyA)) {
|
||||
printf("Test kernel A not found.\n");
|
||||
abort();
|
||||
}
|
||||
MQDependencyTest::Kernel copyB;
|
||||
if (!obj.GetKernel(code_object, "copyB", gpu[0].agent, copyB)) {
|
||||
printf("Test kernel B not found.\n");
|
||||
abort();
|
||||
}
|
||||
MQDependencyTest::Kernel copyC;
|
||||
if (!obj.GetKernel(code_object, "copyC", gpu[0].agent, copyC)) {
|
||||
printf("Test kernel C not found.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
struct args_t {
|
||||
uint32_t* a;
|
||||
uint32_t* b;
|
||||
MQDependencyTest::OCLHiddenArgs hidden;
|
||||
};
|
||||
|
||||
args_t* args;
|
||||
args = static_cast<args_t*>(obj.hsaMalloc(sizeof(args_t), kernarg));
|
||||
memset(args, 0, sizeof(args_t));
|
||||
|
||||
uint32_t* a =
|
||||
static_cast<uint32_t*>(obj.hsaMalloc(64 * sizeof(uint32_t), kernarg));
|
||||
uint32_t* b =
|
||||
static_cast<uint32_t*>(obj.hsaMalloc(64 * sizeof(uint32_t), kernarg));
|
||||
|
||||
memset(a, 0, 64 * sizeof(uint32_t));
|
||||
memset(b, 1, 64 * sizeof(uint32_t));
|
||||
|
||||
// Create queue in gpu agent and prepare a kernel dispatch packet
|
||||
hsa_queue_t* queue1;
|
||||
status = hsa_queue_create(gpu[0].agent, 1024, HSA_QUEUE_TYPE_SINGLE, NULL,
|
||||
NULL, UINT32_MAX, UINT32_MAX, &queue1);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
// Create a signal with a value of 1 and attach it to the first kernel
|
||||
// dispatch packet
|
||||
hsa_signal_t completion_signal_1;
|
||||
status = hsa_signal_create(1, 0, NULL, &completion_signal_1);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
// First dispath packet on queue 1, Kernel A
|
||||
{
|
||||
MQDependencyTest::Aql packet{};
|
||||
packet.header.type = HSA_PACKET_TYPE_KERNEL_DISPATCH;
|
||||
packet.header.barrier = 1;
|
||||
packet.header.acquire = HSA_FENCE_SCOPE_SYSTEM;
|
||||
packet.header.release = HSA_FENCE_SCOPE_SYSTEM;
|
||||
|
||||
packet.dispatch.setup = 1;
|
||||
packet.dispatch.workgroup_size_x = 64;
|
||||
packet.dispatch.workgroup_size_y = 1;
|
||||
packet.dispatch.workgroup_size_z = 1;
|
||||
packet.dispatch.grid_size_x = 64;
|
||||
packet.dispatch.grid_size_y = 1;
|
||||
packet.dispatch.grid_size_z = 1;
|
||||
|
||||
packet.dispatch.group_segment_size = copyA.group;
|
||||
packet.dispatch.private_segment_size = copyA.scratch;
|
||||
packet.dispatch.kernel_object = copyA.handle;
|
||||
|
||||
packet.dispatch.kernarg_address = args;
|
||||
packet.dispatch.completion_signal = completion_signal_1;
|
||||
|
||||
args->a = a;
|
||||
args->b = b;
|
||||
// Tell packet processor of A to launch the first kernel dispatch packet
|
||||
obj.SubmitPacket(queue1, packet);
|
||||
}
|
||||
|
||||
// Create a signal with a value of 1 and attach it to the second kernel
|
||||
// dispatch packet
|
||||
hsa_signal_t completion_signal_2;
|
||||
status = hsa_signal_create(1, 0, NULL, &completion_signal_2);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
hsa_signal_t completion_signal_3;
|
||||
status = hsa_signal_create(1, 0, NULL, &completion_signal_3);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
// Create barrier-AND packet that is enqueued in queue 1
|
||||
{
|
||||
MQDependencyTest::Aql packet{};
|
||||
packet.header.type = HSA_PACKET_TYPE_BARRIER_AND;
|
||||
packet.header.barrier = 1;
|
||||
packet.header.acquire = HSA_FENCE_SCOPE_SYSTEM;
|
||||
packet.header.release = HSA_FENCE_SCOPE_SYSTEM;
|
||||
|
||||
packet.barrier_and.dep_signal[0] = completion_signal_2;
|
||||
obj.SubmitPacket(queue1, packet);
|
||||
}
|
||||
|
||||
// Second dispath packet on queue 1, Kernel C
|
||||
{
|
||||
MQDependencyTest::Aql packet{};
|
||||
packet.header.type = HSA_PACKET_TYPE_KERNEL_DISPATCH;
|
||||
packet.header.barrier = 1;
|
||||
packet.header.acquire = HSA_FENCE_SCOPE_SYSTEM;
|
||||
packet.header.release = HSA_FENCE_SCOPE_SYSTEM;
|
||||
|
||||
packet.dispatch.setup = 1;
|
||||
packet.dispatch.workgroup_size_x = 64;
|
||||
packet.dispatch.workgroup_size_y = 1;
|
||||
packet.dispatch.workgroup_size_z = 1;
|
||||
packet.dispatch.grid_size_x = 64;
|
||||
packet.dispatch.grid_size_y = 1;
|
||||
packet.dispatch.grid_size_z = 1;
|
||||
|
||||
packet.dispatch.group_segment_size = copyC.group;
|
||||
packet.dispatch.private_segment_size = copyC.scratch;
|
||||
packet.dispatch.kernel_object = copyC.handle;
|
||||
packet.dispatch.completion_signal = completion_signal_3;
|
||||
packet.dispatch.kernarg_address = args;
|
||||
|
||||
args->a = a;
|
||||
args->b = b;
|
||||
// Tell packet processor to launch the second kernel dispatch packet
|
||||
obj.SubmitPacket(queue1, packet);
|
||||
}
|
||||
|
||||
// Create queue 2
|
||||
hsa_queue_t* queue2;
|
||||
status = hsa_queue_create(gpu[0].agent, 1024, HSA_QUEUE_TYPE_SINGLE, NULL,
|
||||
NULL, UINT32_MAX, UINT32_MAX, &queue2);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
// Create barrier-AND packet that is enqueued in queue 2
|
||||
{
|
||||
MQDependencyTest::Aql packet{};
|
||||
packet.header.type = HSA_PACKET_TYPE_BARRIER_AND;
|
||||
packet.header.barrier = 1;
|
||||
packet.header.acquire = HSA_FENCE_SCOPE_SYSTEM;
|
||||
packet.header.release = HSA_FENCE_SCOPE_SYSTEM;
|
||||
|
||||
packet.barrier_and.dep_signal[0] = completion_signal_1;
|
||||
obj.SubmitPacket(queue2, packet);
|
||||
}
|
||||
|
||||
// Third dispath packet on queue 2, Kernel B
|
||||
{
|
||||
MQDependencyTest::Aql packet{};
|
||||
packet.header.type = HSA_PACKET_TYPE_KERNEL_DISPATCH;
|
||||
packet.header.barrier = 1;
|
||||
packet.header.acquire = HSA_FENCE_SCOPE_SYSTEM;
|
||||
packet.header.release = HSA_FENCE_SCOPE_SYSTEM;
|
||||
|
||||
packet.dispatch.setup = 1;
|
||||
packet.dispatch.workgroup_size_x = 64;
|
||||
packet.dispatch.workgroup_size_y = 1;
|
||||
packet.dispatch.workgroup_size_z = 1;
|
||||
packet.dispatch.grid_size_x = 64;
|
||||
packet.dispatch.grid_size_y = 1;
|
||||
packet.dispatch.grid_size_z = 1;
|
||||
|
||||
packet.dispatch.group_segment_size = copyB.group;
|
||||
packet.dispatch.private_segment_size = copyB.scratch;
|
||||
packet.dispatch.kernel_object = copyB.handle;
|
||||
|
||||
packet.dispatch.kernarg_address = args;
|
||||
packet.dispatch.completion_signal = completion_signal_2;
|
||||
|
||||
args->a = a;
|
||||
args->b = b;
|
||||
// Tell packet processor to launch the third kernel dispatch packet
|
||||
obj.SubmitPacket(queue2, packet);
|
||||
}
|
||||
|
||||
// Wait on the completion signal
|
||||
hsa_signal_wait_relaxed(completion_signal_1, HSA_SIGNAL_CONDITION_EQ, 0,
|
||||
UINT64_MAX, HSA_WAIT_STATE_BLOCKED);
|
||||
|
||||
// Wait on the completion signal
|
||||
hsa_signal_wait_relaxed(completion_signal_2, HSA_SIGNAL_CONDITION_EQ, 0,
|
||||
UINT64_MAX, HSA_WAIT_STATE_BLOCKED);
|
||||
|
||||
// Wait on the completion signal
|
||||
hsa_signal_wait_relaxed(completion_signal_3, HSA_SIGNAL_CONDITION_EQ, 0,
|
||||
UINT64_MAX, HSA_WAIT_STATE_BLOCKED);
|
||||
|
||||
for (int i = 0; i < 64; i++) {
|
||||
if (a[i] != b[i]) {
|
||||
printf("error at %d: expected %d, got %d\n", i, b[i], a[i]);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
// Clearing data structures and memory
|
||||
status = hsa_signal_destroy(completion_signal_1);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
status = hsa_signal_destroy(completion_signal_2);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
status = hsa_signal_destroy(completion_signal_3);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
if (queue1 != nullptr) {
|
||||
status = hsa_queue_destroy(queue1);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
if (queue2 != nullptr) {
|
||||
status = hsa_queue_destroy(queue2);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
status = hsa_memory_free(a);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
status = hsa_memory_free(b);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
status = hsa_executable_destroy(code_object.executable);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
status = hsa_code_object_reader_destroy(code_object.code_obj_rdr);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
close(code_object.file);
|
||||
}
|
||||
+343
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#ifndef TESTS_FEATURETESTS_PROFILER_DISCRETETESTS_BINARY_MULTIQUEUE_TESTAPP_H_
|
||||
#define TESTS_FEATURETESTS_PROFILER_DISCRETETESTS_BINARY_MULTIQUEUE_TESTAPP_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <hsa/hsa.h>
|
||||
#include <hsa/hsa_api_trace.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "src/utils/exception.h"
|
||||
|
||||
#define ASSERT_EQ(val1, val2) \
|
||||
do { \
|
||||
if ((val1) != val2) { \
|
||||
assert(false); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
struct Device {
|
||||
struct Memory {
|
||||
hsa_amd_memory_pool_t pool;
|
||||
bool fine;
|
||||
bool kernarg;
|
||||
size_t size;
|
||||
size_t granule;
|
||||
};
|
||||
|
||||
hsa_agent_t agent;
|
||||
char name[64];
|
||||
std::vector<Memory> pools;
|
||||
uint32_t fine;
|
||||
uint32_t coarse;
|
||||
static std::vector<hsa_agent_t> all_devices;
|
||||
};
|
||||
|
||||
std::vector<Device> cpu, gpu;
|
||||
Device::Memory kernarg;
|
||||
|
||||
class MQDependencyTest {
|
||||
public:
|
||||
MQDependencyTest() { hsa_init(); }
|
||||
~MQDependencyTest() { hsa_shut_down(); }
|
||||
|
||||
struct CodeObject {
|
||||
hsa_file_t file;
|
||||
hsa_code_object_reader_t code_obj_rdr;
|
||||
hsa_executable_t executable;
|
||||
};
|
||||
|
||||
struct Kernel {
|
||||
uint64_t handle;
|
||||
uint32_t scratch;
|
||||
uint32_t group;
|
||||
uint32_t kernarg_size;
|
||||
uint32_t kernarg_align;
|
||||
};
|
||||
|
||||
union AqlHeader {
|
||||
struct {
|
||||
uint16_t type : 8;
|
||||
uint16_t barrier : 1;
|
||||
uint16_t acquire : 2;
|
||||
uint16_t release : 2;
|
||||
uint16_t reserved : 3;
|
||||
};
|
||||
uint16_t raw;
|
||||
};
|
||||
|
||||
struct BarrierValue {
|
||||
AqlHeader header;
|
||||
uint8_t AmdFormat;
|
||||
uint8_t reserved;
|
||||
uint32_t reserved1;
|
||||
hsa_signal_t signal;
|
||||
hsa_signal_value_t value;
|
||||
hsa_signal_value_t mask;
|
||||
uint32_t cond;
|
||||
uint32_t reserved2;
|
||||
uint64_t reserved3;
|
||||
uint64_t reserved4;
|
||||
hsa_signal_t completion_signal;
|
||||
};
|
||||
|
||||
union Aql {
|
||||
AqlHeader header;
|
||||
hsa_kernel_dispatch_packet_t dispatch;
|
||||
hsa_barrier_and_packet_t barrier_and;
|
||||
hsa_barrier_or_packet_t barrier_or;
|
||||
BarrierValue barrier_value;
|
||||
};
|
||||
|
||||
struct OCLHiddenArgs {
|
||||
uint64_t offset_x;
|
||||
uint64_t offset_y;
|
||||
uint64_t offset_z;
|
||||
void *printf_buffer;
|
||||
void *enqueue;
|
||||
void *enqueue2;
|
||||
void *multi_grid;
|
||||
};
|
||||
|
||||
bool LoadCodeObject(std::string filename, hsa_agent_t agent,
|
||||
CodeObject &code_object) {
|
||||
hsa_status_t err;
|
||||
|
||||
code_object.file = open(filename.c_str(), O_RDONLY);
|
||||
if (code_object.file == -1) {
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
|
||||
err = hsa_code_object_reader_create_from_file(code_object.file,
|
||||
&code_object.code_obj_rdr);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
err = hsa_executable_create_alt(HSA_PROFILE_FULL,
|
||||
HSA_DEFAULT_FLOAT_ROUNDING_MODE_DEFAULT,
|
||||
nullptr, &code_object.executable);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
err = hsa_executable_load_agent_code_object(code_object.executable, agent,
|
||||
code_object.code_obj_rdr,
|
||||
nullptr, nullptr);
|
||||
if (err != HSA_STATUS_SUCCESS) return false;
|
||||
|
||||
err = hsa_executable_freeze(code_object.executable, nullptr);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetKernel(const CodeObject &code_object, std::string kernel,
|
||||
hsa_agent_t agent, Kernel &kern) {
|
||||
hsa_executable_symbol_t symbol;
|
||||
hsa_status_t err = hsa_executable_get_symbol_by_name(
|
||||
code_object.executable, kernel.c_str(), &agent, &symbol);
|
||||
if (err != HSA_STATUS_SUCCESS) {
|
||||
err = hsa_executable_get_symbol_by_name(
|
||||
code_object.executable, (kernel + ".kd").c_str(), &agent, &symbol);
|
||||
if (err != HSA_STATUS_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// printf("\nkernel-name: %s\n", kernel.c_str());
|
||||
err = hsa_executable_symbol_get_info(
|
||||
symbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_OBJECT, &kern.handle);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
err = hsa_executable_symbol_get_info(
|
||||
symbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_PRIVATE_SEGMENT_SIZE,
|
||||
&kern.scratch);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
// printf("Scratch: %d\n", kern.scratch);
|
||||
|
||||
err = hsa_executable_symbol_get_info(
|
||||
symbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_GROUP_SEGMENT_SIZE,
|
||||
&kern.group);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
// printf("LDS: %d\n", kern.group);
|
||||
|
||||
// Remaining needs code object v2 or comgr.
|
||||
err = hsa_executable_symbol_get_info(
|
||||
symbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_KERNARG_SEGMENT_SIZE,
|
||||
&kern.kernarg_size);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
// printf("Kernarg Size: %d\n", kern.kernarg_size);
|
||||
|
||||
err = hsa_executable_symbol_get_info(
|
||||
symbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_KERNARG_SEGMENT_ALIGNMENT,
|
||||
&kern.kernarg_align);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
// printf("Kernarg Align: %d\n", kern.kernarg_align);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not for parallel insertion.
|
||||
bool SubmitPacket(hsa_queue_t *queue, Aql &pkt) {
|
||||
size_t mask = queue->size - 1;
|
||||
Aql *ring = static_cast<Aql *>(queue->base_address);
|
||||
|
||||
uint64_t write = hsa_queue_load_write_index_relaxed(queue);
|
||||
uint64_t read = hsa_queue_load_read_index_relaxed(queue);
|
||||
if (write - read + 1 > queue->size) return false;
|
||||
|
||||
Aql &dst = ring[write & mask];
|
||||
|
||||
uint16_t header = pkt.header.raw;
|
||||
pkt.header.raw = dst.header.raw;
|
||||
dst = pkt;
|
||||
__atomic_store_n(&dst.header.raw, header, __ATOMIC_RELEASE);
|
||||
pkt.header.raw = header;
|
||||
|
||||
hsa_queue_store_write_index_release(queue, write + 1);
|
||||
hsa_signal_store_screlease(queue->doorbell_signal, write);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void *hsaMalloc(size_t size, const Device::Memory &mem) {
|
||||
void *ret;
|
||||
hsa_status_t err = hsa_amd_memory_pool_allocate(mem.pool, size, 0, &ret);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
err = hsa_amd_agents_allow_access(Device::all_devices.size(),
|
||||
&Device::all_devices[0], nullptr, ret);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *hsaMalloc(size_t size, const Device &dev, bool fine) {
|
||||
uint32_t index = fine ? dev.fine : dev.coarse;
|
||||
assert(index != -1u && "Memory type unavailable.");
|
||||
return hsaMalloc(size, dev.pools[index]);
|
||||
}
|
||||
|
||||
bool DeviceDiscovery() {
|
||||
hsa_status_t err;
|
||||
err = hsa_iterate_agents(
|
||||
[](hsa_agent_t agent, void *) {
|
||||
hsa_status_t err;
|
||||
|
||||
Device dev;
|
||||
dev.agent = agent;
|
||||
|
||||
dev.fine = -1u;
|
||||
dev.coarse = -1u;
|
||||
|
||||
err = hsa_agent_get_info(agent, HSA_AGENT_INFO_NAME, dev.name);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
hsa_device_type_t type;
|
||||
err = hsa_agent_get_info(agent, HSA_AGENT_INFO_DEVICE, &type);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
err = hsa_amd_agent_iterate_memory_pools(
|
||||
agent,
|
||||
[](hsa_amd_memory_pool_t pool, void *data) {
|
||||
std::vector<Device::Memory> &pools =
|
||||
*reinterpret_cast<std::vector<Device::Memory> *>(data);
|
||||
hsa_status_t err;
|
||||
|
||||
hsa_amd_segment_t segment;
|
||||
err = hsa_amd_memory_pool_get_info(
|
||||
pool, HSA_AMD_MEMORY_POOL_INFO_SEGMENT, &segment);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
if (segment != HSA_AMD_SEGMENT_GLOBAL)
|
||||
return HSA_STATUS_SUCCESS;
|
||||
|
||||
uint32_t flags;
|
||||
err = hsa_amd_memory_pool_get_info(
|
||||
pool, HSA_AMD_MEMORY_POOL_INFO_GLOBAL_FLAGS, &flags);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
Device::Memory mem;
|
||||
mem.pool = pool;
|
||||
mem.fine =
|
||||
(flags & HSA_AMD_MEMORY_POOL_GLOBAL_FLAG_FINE_GRAINED);
|
||||
mem.kernarg =
|
||||
(flags & HSA_AMD_MEMORY_POOL_GLOBAL_FLAG_KERNARG_INIT);
|
||||
|
||||
err = hsa_amd_memory_pool_get_info(
|
||||
pool, HSA_AMD_MEMORY_POOL_INFO_SIZE, &mem.size);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
err = hsa_amd_memory_pool_get_info(
|
||||
pool, HSA_AMD_MEMORY_POOL_INFO_RUNTIME_ALLOC_GRANULE,
|
||||
&mem.granule);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
pools.push_back(mem);
|
||||
return HSA_STATUS_SUCCESS;
|
||||
},
|
||||
static_cast<void *>(&dev.pools));
|
||||
|
||||
if (!dev.pools.empty()) {
|
||||
for (size_t i = 0; i < dev.pools.size(); i++) {
|
||||
if (dev.pools[i].fine && dev.pools[i].kernarg && dev.fine == -1u)
|
||||
dev.fine = i;
|
||||
if (dev.pools[i].fine && !dev.pools[i].kernarg) dev.fine = i;
|
||||
if (!dev.pools[i].fine) dev.coarse = i;
|
||||
}
|
||||
|
||||
if (type == HSA_DEVICE_TYPE_CPU)
|
||||
cpu.push_back(dev);
|
||||
else
|
||||
gpu.push_back(dev);
|
||||
|
||||
Device::all_devices.push_back(dev.agent);
|
||||
}
|
||||
|
||||
return HSA_STATUS_SUCCESS;
|
||||
},
|
||||
nullptr);
|
||||
|
||||
[]() {
|
||||
for (auto &dev : cpu) {
|
||||
for (auto &mem : dev.pools) {
|
||||
if (mem.fine && mem.kernarg) {
|
||||
kernarg = mem;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}();
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
if (cpu.empty() || gpu.empty() || kernarg.pool.handle == 0) return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
#endif // TESTS_FEATURETESTS_PROFILER_DISCRETETESTS_BINARY_MULTIQUEUE_TESTAPP_H_
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/** \mainpage ROC Profiler Binary Test
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test is to test ROC profiler as a binary against a
|
||||
* multithreaded application.Test application launches an empty kernel
|
||||
* on multiple threads.
|
||||
*
|
||||
* The test then parses the csv and verifies if the nuber of kernel dispatches
|
||||
* are equal to number of threads launched in test application.
|
||||
*
|
||||
* Test also does some basic verification if counter values are non-negative
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/csv_parser.h"
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
// kernel dispatch count test
|
||||
int DispatchCountTest(std::string profiler_output) {
|
||||
CSVParser parser;
|
||||
parser.ParseCSV(profiler_output);
|
||||
countermap counter_map = parser.GetCounterMap();
|
||||
|
||||
int dispatch_counter = 0;
|
||||
for (auto i = 0; i < counter_map.size(); i++) {
|
||||
std::string* dispatch_id = parser.ReadCounter(i, 1);
|
||||
if (dispatch_id != nullptr) {
|
||||
if (dispatch_id->find("dispatch") != std::string::npos) {
|
||||
dispatch_counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dispatch count test: Number of dispatches must be equal to
|
||||
// number of kernel launches in test_app
|
||||
if (dispatch_counter == GetNumberOfCores()) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string ReadProfilerBuffer(const char* cmd) {
|
||||
std::vector<char> buffer(1028);
|
||||
std::string profiler_output;
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
|
||||
if (!pipe) {
|
||||
throw std::runtime_error("popen() failed!");
|
||||
}
|
||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
||||
profiler_output += buffer.data();
|
||||
}
|
||||
return profiler_output;
|
||||
}
|
||||
|
||||
std::string InitCounterTest() {
|
||||
std::string input_path = GetRunningPath("profiler_multithreaded_test");
|
||||
std::string rocprofv2_path = GetRunningPath(
|
||||
"build/tests/featuretests/profiler/profiler_multithreaded_test");
|
||||
std::stringstream command;
|
||||
command << rocprofv2_path + "./rocprofv2 -i "
|
||||
<< input_path + "basic_metrics.txt "
|
||||
<< input_path + "multithreaded_testapp";
|
||||
std::string result = ReadProfilerBuffer(command.str().c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int test_status = -1;
|
||||
|
||||
// initialize kernel dispatch test
|
||||
std::string profiler_output = InitCounterTest();
|
||||
// kernel dispatch count test
|
||||
test_status = DispatchCountTest(profiler_output);
|
||||
|
||||
return test_status;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/******************************************************************************
|
||||
Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*******************************************************************************/
|
||||
|
||||
/** \mainpage ROC Profiler Multi-Threaded Test Application
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* Test application launches an empty kernel on multiple threads.
|
||||
*
|
||||
* In subsequent tests, ROC profiler is run against this applicaiton
|
||||
* to confirm if collected contexts are valid.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <hip/hip_runtime.h>
|
||||
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
/** \mainpage ROC Profiler Test APplication
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test application is to launch an empty kernel
|
||||
* on multiple threads and multiple gpu's.
|
||||
*
|
||||
* Number of threads are caluculated based on the cores in the system
|
||||
* Number of gpus's are calculated based on the gpu's in the system
|
||||
*/
|
||||
|
||||
// empty kernel
|
||||
__global__ void kernel() {}
|
||||
|
||||
// launches kernel on multiple gpu's
|
||||
void KernelLaunch() {
|
||||
// Multi-GPU
|
||||
int gpu_count = 0;
|
||||
hipGetDeviceCount(&gpu_count);
|
||||
|
||||
for (uint32_t gpu_id = 0; gpu_id < gpu_count; gpu_id++) {
|
||||
// run empty kernel
|
||||
kernel<<<1, 1>>>();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// create as many threads as number of cores in system
|
||||
int threads_count = GetNumberOfCores();
|
||||
|
||||
// create a pool of thrads
|
||||
std::vector<std::thread> threads(threads_count);
|
||||
|
||||
// launch kernel on each thread
|
||||
for (int n = 0; n < threads_count; ++n) {
|
||||
threads[n] = std::thread(KernelLaunch);
|
||||
}
|
||||
// wait for all kernel launches to complete
|
||||
for (int n = 0; n < threads_count; ++n) {
|
||||
threads[n].join();
|
||||
}
|
||||
}
|
||||
Yeni konuda referans
Bir kullanıcı engelle