hsa-runtime integration
Change-Id: I48968966ffe164218ebff88d0e3a1268e96bf1dd
이 커밋은 다음에 포함됨:
@@ -0,0 +1,15 @@
|
||||
#
|
||||
# Source files for Rocr Utils library
|
||||
#
|
||||
file( GLOB MODULE_SRC "*.cpp" )
|
||||
|
||||
#
|
||||
# Header files include path(s).
|
||||
#
|
||||
include_directories ( $ENV{ROCR_INC_DIR} )
|
||||
|
||||
#
|
||||
# Build Utils as a Static Library object
|
||||
#
|
||||
add_library( ${UTIL_LIB} STATIC ${MODULE_SRC} )
|
||||
target_link_libraries( ${UTIL_LIB} c stdc++ dl pthread rt )
|
||||
@@ -0,0 +1,230 @@
|
||||
/**********************************************************************
|
||||
Copyright ©2013 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
provided that the following conditions are met:
|
||||
|
||||
• Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
• Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
********************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
#include <time.h>
|
||||
|
||||
#include "helper_funcs.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
void error(std::string errorMsg) { std::cout << "Error: " << errorMsg << std::endl; }
|
||||
|
||||
/*
|
||||
* Prints no more than 256 elements of the given array.
|
||||
* Prints full array if length is less than 256.
|
||||
* Prints Array name followed by elements.
|
||||
*/
|
||||
template <typename T>
|
||||
void printArray(const std::string header, const T* data, const int width, const int height) {
|
||||
std::cout << header << " :\n";
|
||||
for (int i = 0; i < height; i++) {
|
||||
std::cout << "> ";
|
||||
for (int j = 0; j < width; j++) {
|
||||
std::cout << data[i * width + j] << " ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool fillRandom(T* arrayPtr, const int width, const int height, const T rangeMin, const T rangeMax,
|
||||
unsigned int seed) {
|
||||
if (!arrayPtr) {
|
||||
error("Cannot fill array. NULL pointer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!seed) seed = (unsigned int)time(NULL);
|
||||
|
||||
srand(seed);
|
||||
double range = double(rangeMax - rangeMin) + 1.0;
|
||||
|
||||
/* random initialisation of input */
|
||||
for (int i = 0; i < height; i++)
|
||||
for (int j = 0; j < width; j++) {
|
||||
int index = i * width + j;
|
||||
arrayPtr[index] = rangeMin + T(range * rand() / (RAND_MAX + 1.0));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T> bool fillPos(T* arrayPtr, const int width, const int height) {
|
||||
if (!arrayPtr) {
|
||||
error("Cannot fill array. NULL pointer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* initialisation of input with positions*/
|
||||
for (T i = 0; i < height; i++)
|
||||
for (T j = 0; j < width; j++) {
|
||||
T index = i * width + j;
|
||||
arrayPtr[index] = index;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool fillConstant(T* arrayPtr, const int width, const int height, const T val) {
|
||||
if (!arrayPtr) {
|
||||
error("Cannot fill array. NULL pointer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* initialisation of input with constant value*/
|
||||
for (int i = 0; i < height; i++)
|
||||
for (int j = 0; j < width; j++) {
|
||||
int index = i * width + j;
|
||||
arrayPtr[index] = val;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T> T roundToPowerOf2(T val) {
|
||||
int bytes = sizeof(T);
|
||||
|
||||
val--;
|
||||
for (int i = 0; i < bytes; i++) val |= val >> (1 << i);
|
||||
val++;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T> bool isPowerOf2(T val) {
|
||||
long long _val = val;
|
||||
return (((_val & (-_val)) - _val == 0) && (_val != 0));
|
||||
}
|
||||
|
||||
template <typename T> std::string toString(T t, std::ios_base& (*r)(std::ios_base&)) {
|
||||
std::ostringstream output;
|
||||
output << r << t;
|
||||
return output.str();
|
||||
}
|
||||
|
||||
bool compare(const float* refData, const float* data, const int length, const float epsilon) {
|
||||
float error = 0.0f;
|
||||
float ref = 0.0f;
|
||||
|
||||
for (int i = 1; i < length; ++i) {
|
||||
float diff = refData[i] - data[i];
|
||||
error += diff * diff;
|
||||
ref += refData[i] * refData[i];
|
||||
}
|
||||
|
||||
float normRef = ::sqrtf((float)ref);
|
||||
if (::fabs((float)ref) < 1e-7f) {
|
||||
return false;
|
||||
}
|
||||
float normError = ::sqrtf((float)error);
|
||||
error = normError / normRef;
|
||||
|
||||
return error < epsilon;
|
||||
}
|
||||
|
||||
bool compare(const double* refData, const double* data, const int length, const double epsilon) {
|
||||
double error = 0.0;
|
||||
double ref = 0.0;
|
||||
|
||||
for (int i = 1; i < length; ++i) {
|
||||
double diff = refData[i] - data[i];
|
||||
error += diff * diff;
|
||||
ref += refData[i] * refData[i];
|
||||
}
|
||||
|
||||
double normRef = ::sqrt((double)ref);
|
||||
if (::fabs((double)ref) < 1e-7) {
|
||||
return false;
|
||||
}
|
||||
double normError = ::sqrt((double)error);
|
||||
error = normError / normRef;
|
||||
|
||||
return error < epsilon;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Template Instantiations
|
||||
/////////////////////////////////////////////////////////////////
|
||||
template void printArray<short>(const std::string, const short*, int, int);
|
||||
template void printArray<unsigned char>(const std::string, const unsigned char*, int, int);
|
||||
template void printArray<unsigned int>(const std::string, const unsigned int*, int, int);
|
||||
template void printArray<int>(const std::string, const int*, int, int);
|
||||
template void printArray<long>(const std::string, const long*, int, int);
|
||||
template void printArray<float>(const std::string, const float*, int, int);
|
||||
template void printArray<double>(const std::string, const double*, int, int);
|
||||
|
||||
template bool fillRandom<unsigned char>(unsigned char* arrayPtr, const int width, const int height,
|
||||
unsigned char rangeMin, unsigned char rangeMax,
|
||||
unsigned int seed);
|
||||
template bool fillRandom<unsigned int>(unsigned int* arrayPtr, const int width, const int height,
|
||||
unsigned int rangeMin, unsigned int rangeMax,
|
||||
unsigned int seed);
|
||||
template bool fillRandom<int>(int* arrayPtr, const int width, const int height, int rangeMin,
|
||||
int rangeMax, unsigned int seed);
|
||||
template bool fillRandom<long>(long* arrayPtr, const int width, const int height, long rangeMin,
|
||||
long rangeMax, unsigned int seed);
|
||||
template bool fillRandom<float>(float* arrayPtr, const int width, const int height, float rangeMin,
|
||||
float rangeMax, unsigned int seed);
|
||||
template bool fillRandom<double>(double* arrayPtr, const int width, const int height,
|
||||
double rangeMin, double rangeMax, unsigned int seed);
|
||||
|
||||
template short roundToPowerOf2<short>(short val);
|
||||
template unsigned int roundToPowerOf2<unsigned int>(unsigned int val);
|
||||
template int roundToPowerOf2<int>(int val);
|
||||
template long roundToPowerOf2<long>(long val);
|
||||
|
||||
template bool isPowerOf2<short>(short val);
|
||||
template bool isPowerOf2<unsigned int>(unsigned int val);
|
||||
template bool isPowerOf2<int>(int val);
|
||||
template bool isPowerOf2<long>(long val);
|
||||
|
||||
template <> bool fillPos<short>(short* arrayPtr, const int width, const int height);
|
||||
template <> bool fillPos<unsigned int>(unsigned int* arrayPtr, const int width, const int height);
|
||||
template <> bool fillPos<int>(int* arrayPtr, const int width, const int height);
|
||||
template <> bool fillPos<long>(long* arrayPtr, const int width, const int height);
|
||||
|
||||
template <>
|
||||
bool fillConstant<short>(short* arrayPtr, const int width, const int height, const short val);
|
||||
template <>
|
||||
bool fillConstant(unsigned int* arrayPtr, const int width, const int height,
|
||||
const unsigned int val);
|
||||
template <> bool fillConstant(int* arrayPtr, const int width, const int height, const int val);
|
||||
template <> bool fillConstant(long* arrayPtr, const int width, const int height, const long val);
|
||||
template <> bool fillConstant(long* arrayPtr, const int width, const int height, const long val);
|
||||
template <> bool fillConstant(long* arrayPtr, const int width, const int height, const long val);
|
||||
|
||||
template std::string toString<char>(char t, std::ios_base& (*r)(std::ios_base&));
|
||||
template std::string toString<short>(short t, std::ios_base& (*r)(std::ios_base&));
|
||||
template std::string toString<unsigned int>(unsigned int t, std::ios_base& (*r)(std::ios_base&));
|
||||
template std::string toString<int>(int t, std::ios_base& (*r)(std::ios_base&));
|
||||
template std::string toString<long>(long t, std::ios_base& (*r)(std::ios_base&));
|
||||
template std::string toString<float>(float t, std::ios_base& (*r)(std::ios_base&));
|
||||
template std::string toString<double>(double t, std::ios_base& (*r)(std::ios_base&));
|
||||
@@ -0,0 +1,90 @@
|
||||
/**********************************************************************
|
||||
Copyright ©2013 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
provided that the following conditions are met:
|
||||
|
||||
• Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
• Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
********************************************************************/
|
||||
#ifndef _HELPER_FUNCS_H_
|
||||
#define _HELPER_FUNCS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* compare template version
|
||||
* compare data to check error
|
||||
* @param refData templated input
|
||||
* @param data templated input
|
||||
* @param length number of values to compare
|
||||
* @param epsilon errorWindow
|
||||
*/
|
||||
bool compare(const float* refData, const float* data, const int length,
|
||||
const float epsilon = 1e-6f);
|
||||
bool compare(const double* refData, const double* data, const int length,
|
||||
const double epsilon = 1e-6);
|
||||
|
||||
/**
|
||||
* printArray
|
||||
* displays a array on std::out
|
||||
*/
|
||||
template <typename T>
|
||||
void printArray(const std::string header, const T* data, const int width, const int height);
|
||||
|
||||
|
||||
/**
|
||||
* fillRandom
|
||||
* fill array with random values
|
||||
*/
|
||||
template <typename T>
|
||||
bool fillRandom(T* arrayPtr, const int width, const int height, const T rangeMin, const T rangeMax,
|
||||
unsigned int seed = 123);
|
||||
|
||||
/**
|
||||
* fillPos
|
||||
* fill the specified positions
|
||||
*/
|
||||
template <typename T> bool fillPos(T* arrayPtr, const int width, const int height);
|
||||
|
||||
/**
|
||||
* fillConstant
|
||||
* fill the array with constant value
|
||||
*/
|
||||
template <typename T>
|
||||
bool fillConstant(T* arrayPtr, const int width, const int height, const T val);
|
||||
|
||||
|
||||
/**
|
||||
* roundToPowerOf2
|
||||
* rounds to a power of 2
|
||||
*/
|
||||
template <typename T> T roundToPowerOf2(T val);
|
||||
|
||||
/**
|
||||
* isPowerOf2
|
||||
* checks if input is a power of 2
|
||||
*/
|
||||
template <typename T> bool isPowerOf2(T val);
|
||||
|
||||
/**
|
||||
* toString
|
||||
* convert a T type to string
|
||||
*/
|
||||
template <typename T> std::string toString(T t, std::ios_base& (*r)(std::ios_base&));
|
||||
|
||||
#endif // _HELPER_FUNCS_H_
|
||||
@@ -0,0 +1,473 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <cassert>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "hsa.h"
|
||||
#include "hsa_rsrc_factory.h"
|
||||
#include "hsa_ext_finalize.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Provide access to command line arguments passed in by user
|
||||
uint32_t hsa_cmdline_arg_cnt;
|
||||
char** hsa_cmdline_arg_list;
|
||||
|
||||
// Callback function to find and bind kernarg region of an agent
|
||||
static hsa_status_t find_memregions(hsa_region_t region, void* data) {
|
||||
hsa_region_global_flag_t flags;
|
||||
hsa_region_segment_t segment_id;
|
||||
|
||||
hsa_region_get_info(region, HSA_REGION_INFO_SEGMENT, &segment_id);
|
||||
if (segment_id != HSA_REGION_SEGMENT_GLOBAL) {
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
AgentInfo* agent_info = (AgentInfo*)data;
|
||||
hsa_region_get_info(region, HSA_REGION_INFO_GLOBAL_FLAGS, &flags);
|
||||
if (flags & HSA_REGION_GLOBAL_FLAG_COARSE_GRAINED) {
|
||||
agent_info->coarse_region = region;
|
||||
}
|
||||
|
||||
if (flags & HSA_REGION_GLOBAL_FLAG_KERNARG) {
|
||||
agent_info->kernarg_region = region;
|
||||
}
|
||||
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Callback function to get the number of agents
|
||||
static hsa_status_t get_hsa_agents(hsa_agent_t agent, void* data) {
|
||||
// Copy handle of agent and increment number of agents reported
|
||||
HsaRsrcFactory* rsrcFactory = reinterpret_cast<HsaRsrcFactory*>(data);
|
||||
|
||||
// Determine if device is a Gpu agent
|
||||
hsa_status_t status;
|
||||
hsa_device_type_t type;
|
||||
status = hsa_agent_get_info(agent, HSA_AGENT_INFO_DEVICE, &type);
|
||||
if (type == HSA_DEVICE_TYPE_DSP) {
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (type == HSA_DEVICE_TYPE_CPU) {
|
||||
AgentInfo* agent_info = reinterpret_cast<AgentInfo*>(malloc(sizeof(AgentInfo)));
|
||||
agent_info->dev_id = agent;
|
||||
agent_info->dev_type = HSA_DEVICE_TYPE_CPU;
|
||||
rsrcFactory->AddAgentInfo(agent_info, false);
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Device is a Gpu agent, build an instance of AgentInfo
|
||||
AgentInfo* agent_info = reinterpret_cast<AgentInfo*>(malloc(sizeof(AgentInfo)));
|
||||
agent_info->dev_id = agent;
|
||||
agent_info->dev_type = HSA_DEVICE_TYPE_GPU;
|
||||
hsa_agent_get_info(agent, HSA_AGENT_INFO_NAME, agent_info->name);
|
||||
agent_info->max_wave_size = 0;
|
||||
hsa_agent_get_info(agent, HSA_AGENT_INFO_WAVEFRONT_SIZE, &agent_info->max_wave_size);
|
||||
agent_info->max_queue_size = 0;
|
||||
hsa_agent_get_info(agent, HSA_AGENT_INFO_QUEUE_MAX_SIZE, &agent_info->max_queue_size);
|
||||
agent_info->profile = hsa_profile_t(108);
|
||||
hsa_agent_get_info(agent, HSA_AGENT_INFO_PROFILE, &agent_info->profile);
|
||||
|
||||
// Initialize memory regions to zero
|
||||
agent_info->kernarg_region.handle = 0;
|
||||
agent_info->coarse_region.handle = 0;
|
||||
|
||||
// Find and Bind Memory regions of the Gpu agent
|
||||
hsa_agent_iterate_regions(agent, find_memregions, agent_info);
|
||||
|
||||
// Save the instance of AgentInfo
|
||||
rsrcFactory->AddAgentInfo(agent_info, true);
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Definitions for Static Data members of the class
|
||||
char* HsaRsrcFactory::brig_path_ = NULL;
|
||||
uint32_t HsaRsrcFactory::num_cus_ = 4;
|
||||
uint32_t HsaRsrcFactory::num_waves_;
|
||||
uint32_t HsaRsrcFactory::num_workitems_;
|
||||
uint32_t HsaRsrcFactory::kernel_loop_count_;
|
||||
bool HsaRsrcFactory::print_debug_info_ = false;
|
||||
|
||||
char* HsaRsrcFactory::num_cus_key_ = "num_cus";
|
||||
char* HsaRsrcFactory::brig_path_key_ = "brig_path";
|
||||
char* HsaRsrcFactory::num_waves_key_ = "waves_per_cu";
|
||||
char* HsaRsrcFactory::num_workitems_key_ = "workitems_per_wave";
|
||||
char* HsaRsrcFactory::print_debug_key_ = "print_debug";
|
||||
char* HsaRsrcFactory::kernel_loop_count_key_ = "kernel_loop_count";
|
||||
|
||||
// Constructor of the class
|
||||
HsaRsrcFactory::HsaRsrcFactory() {
|
||||
// Initialize the Hsa Runtime
|
||||
hsa_status_t status = hsa_init();
|
||||
check("Error in hsa_init", status);
|
||||
|
||||
// Discover the set of Gpu devices available on the platform
|
||||
status = hsa_iterate_agents(get_hsa_agents, this);
|
||||
check("Error Calling hsa_iterate_agents", status);
|
||||
|
||||
// Process command line arguments
|
||||
ProcessCmdline();
|
||||
}
|
||||
|
||||
// Destructor of the class
|
||||
HsaRsrcFactory::~HsaRsrcFactory() {}
|
||||
|
||||
// Get the count of Hsa Gpu Agents available on the platform
|
||||
//
|
||||
// @return uint32_t Number of Gpu agents on platform
|
||||
//
|
||||
uint32_t HsaRsrcFactory::GetCountOfGpuAgents() { return uint32_t(gpu_list_.size()); }
|
||||
|
||||
// Get the count of Hsa Cpu Agents available on the platform
|
||||
//
|
||||
// @return uint32_t Number of Cpu agents on platform
|
||||
//
|
||||
uint32_t HsaRsrcFactory::GetCountOfCpuAgents() { return uint32_t(cpu_list_.size()); }
|
||||
|
||||
// Get the AgentInfo handle of a Gpu device
|
||||
//
|
||||
// @param idx Gpu Agent at specified index
|
||||
//
|
||||
// @param agent_info Output parameter updated with AgentInfo
|
||||
//
|
||||
// @return bool true if successful, false otherwise
|
||||
//
|
||||
bool HsaRsrcFactory::GetGpuAgentInfo(uint32_t idx, AgentInfo** agent_info) {
|
||||
// Determine if request is valid
|
||||
uint32_t size = uint32_t(gpu_list_.size());
|
||||
if (idx >= size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy AgentInfo from specified index
|
||||
*agent_info = gpu_list_[idx];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the AgentInfo handle of a Cpu device
|
||||
//
|
||||
// @param idx Cpu Agent at specified index
|
||||
//
|
||||
// @param agent_info Output parameter updated with AgentInfo
|
||||
//
|
||||
// @return bool true if successful, false otherwise
|
||||
//
|
||||
bool HsaRsrcFactory::GetCpuAgentInfo(uint32_t idx, AgentInfo** agent_info) {
|
||||
// Determine if request is valid
|
||||
uint32_t size = uint32_t(cpu_list_.size());
|
||||
if (idx >= size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy AgentInfo from specified index
|
||||
*agent_info = cpu_list_[idx];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create a Queue object and return its handle. The queue object is expected
|
||||
// to support user requested number of Aql dispatch packets.
|
||||
//
|
||||
// @param agent_info Gpu Agent on which to create a queue object
|
||||
//
|
||||
// @param num_Pkts Number of packets to be held by queue
|
||||
//
|
||||
// @param queue Output parameter updated with handle of queue object
|
||||
//
|
||||
// @return bool true if successful, false otherwise
|
||||
//
|
||||
bool HsaRsrcFactory::CreateQueue(AgentInfo* agent_info, uint32_t num_pkts, hsa_queue_t** queue) {
|
||||
hsa_status_t status;
|
||||
status = hsa_queue_create(agent_info->dev_id, num_pkts, HSA_QUEUE_TYPE_MULTI, NULL, NULL,
|
||||
UINT32_MAX, UINT32_MAX, queue);
|
||||
return (status == HSA_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
// Create a Signal object and return its handle.
|
||||
//
|
||||
// @param value Initial value of signal object
|
||||
//
|
||||
// @param signal Output parameter updated with handle of signal object
|
||||
//
|
||||
// @return bool true if successful, false otherwise
|
||||
//
|
||||
bool HsaRsrcFactory::CreateSignal(uint32_t value, hsa_signal_t* signal) {
|
||||
hsa_status_t status;
|
||||
status = hsa_signal_create(value, 0, NULL, signal);
|
||||
return (status == HSA_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
// Allocate memory for use by a kernel of specified size in specified
|
||||
// agent's memory region. Currently supports Global segment whose Kernarg
|
||||
// flag set.
|
||||
//
|
||||
// @param agent_info Agent from whose memory region to allocate
|
||||
//
|
||||
// @param size Size of memory in terms of bytes
|
||||
//
|
||||
// @return uint8_t* Pointer to buffer, null if allocation fails.
|
||||
//
|
||||
uint8_t* HsaRsrcFactory::AllocateLocalMemory(AgentInfo* agent_info, size_t size) {
|
||||
hsa_status_t status;
|
||||
uint8_t* buffer = NULL;
|
||||
|
||||
if (agent_info->coarse_region.handle != 0) {
|
||||
// Allocate in local memory if it is available
|
||||
status = hsa_memory_allocate(agent_info->coarse_region, size, (void**)&buffer);
|
||||
if (status == HSA_STATUS_SUCCESS) {
|
||||
status = hsa_memory_assign_agent(buffer, agent_info->dev_id, HSA_ACCESS_PERMISSION_RW);
|
||||
}
|
||||
} else {
|
||||
// Allocate in system memory if local memory is not available
|
||||
status = hsa_memory_allocate(agent_info->kernarg_region, size, (void**)&buffer);
|
||||
}
|
||||
|
||||
return (status == HSA_STATUS_SUCCESS) ? buffer : NULL;
|
||||
}
|
||||
|
||||
// Allocate memory tp pass kernel parameters.
|
||||
//
|
||||
// @param agent_info Agent from whose memory region to allocate
|
||||
//
|
||||
// @param size Size of memory in terms of bytes
|
||||
//
|
||||
// @return uint8_t* Pointer to buffer, null if allocation fails.
|
||||
//
|
||||
uint8_t* HsaRsrcFactory::AllocateSysMemory(AgentInfo* agent_info, size_t size) {
|
||||
hsa_status_t status;
|
||||
uint8_t* buffer = NULL;
|
||||
status = hsa_memory_allocate(agent_info->kernarg_region, size, (void**)&buffer);
|
||||
return (status == HSA_STATUS_SUCCESS) ? buffer : NULL;
|
||||
}
|
||||
|
||||
bool HsaRsrcFactory::TransferData(uint8_t* dest_buff, uint8_t* src_buff, uint32_t length,
|
||||
bool host_to_dev) {
|
||||
hsa_status_t status;
|
||||
status = hsa_memory_copy(dest_buff, src_buff, length);
|
||||
return (status == HSA_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
// Fake method for compilation steps only
|
||||
uint8_t* HsaRsrcFactory::AllocateMemory(AgentInfo* agent_info, size_t size) {
|
||||
hsa_status_t status;
|
||||
uint8_t* buffer = NULL;
|
||||
status = hsa_memory_allocate(agent_info->kernarg_region, size, (void**)&buffer);
|
||||
return (status == HSA_STATUS_SUCCESS) ? buffer : NULL;
|
||||
}
|
||||
|
||||
// Loads an Assembled Brig file and Finalizes it into Device Isa
|
||||
//
|
||||
// @param agent_info Gpu device for which to finalize
|
||||
//
|
||||
// @param brig_path File path of the Assembled Brig file
|
||||
//
|
||||
// @param kernel_name Name of the kernel to finalize
|
||||
//
|
||||
// @param code_desc Handle of finalized Code Descriptor that could
|
||||
// be used to submit for execution
|
||||
//
|
||||
// @return bool true if successful, false otherwise
|
||||
//
|
||||
bool HsaRsrcFactory::LoadAndFinalize(AgentInfo* agent_info, const char* brig_path,
|
||||
char* kernel_name, hsa_executable_symbol_t* code_desc) {
|
||||
// Finalize the Hsail object into code object
|
||||
hsa_status_t status;
|
||||
hsa_code_object_t code_object;
|
||||
|
||||
// Build the code object filename
|
||||
std::string filename(brig_path);
|
||||
std::cout << "Code object filename: " << filename << std::endl;
|
||||
|
||||
// Open the file containing code object
|
||||
std::ifstream codeStream(filename.c_str(), std::ios::binary | std::ios::ate);
|
||||
if (!codeStream) {
|
||||
std::cout << "Error: failed to load " << filename << std::endl;
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate memory to read in code object from file
|
||||
size_t size = std::string::size_type(codeStream.tellg());
|
||||
char* codeBuff = (char*)AllocateSysMemory(agent_info, size);
|
||||
if (!codeBuff) {
|
||||
std::cout << "Error: failed to allocate memory for code object." << std::endl;
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the code object into allocated memory
|
||||
codeStream.seekg(0, std::ios::beg);
|
||||
std::copy(std::istreambuf_iterator<char>(codeStream), std::istreambuf_iterator<char>(), codeBuff);
|
||||
|
||||
// De-Serialize the code object that has been read into memory
|
||||
status = hsa_code_object_deserialize(codeBuff, size, NULL, &code_object);
|
||||
if (status != HSA_STATUS_SUCCESS) {
|
||||
std::cout << "Failed to deserialize code object" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create executable.
|
||||
hsa_executable_t hsaExecutable;
|
||||
// status = hsa_executable_create(agent_info->profile,
|
||||
status =
|
||||
hsa_executable_create(HSA_PROFILE_FULL, HSA_EXECUTABLE_STATE_UNFROZEN, "", &hsaExecutable);
|
||||
check("Error in creating executable object", status);
|
||||
|
||||
// Load code object.
|
||||
status = hsa_executable_load_code_object(hsaExecutable, agent_info->dev_id, code_object, "");
|
||||
check("Error in loading executable object", status);
|
||||
|
||||
// Freeze executable.
|
||||
status = hsa_executable_freeze(hsaExecutable, "");
|
||||
check("Error in freezing executable object", status);
|
||||
|
||||
// Get symbol handle.
|
||||
hsa_executable_symbol_t kernelSymbol;
|
||||
status = hsa_executable_get_symbol(hsaExecutable, NULL, kernel_name, agent_info->dev_id, 0,
|
||||
&kernelSymbol);
|
||||
check("Error in looking up kernel symbol", status);
|
||||
|
||||
// Update output parameter
|
||||
*code_desc = kernelSymbol;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add an instance of AgentInfo representing a Hsa Gpu agent
|
||||
void HsaRsrcFactory::AddAgentInfo(AgentInfo* agent_info, bool gpu) {
|
||||
// Add input to Gpu list
|
||||
if (gpu) {
|
||||
gpu_list_.push_back(agent_info);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add input to Cpu list
|
||||
cpu_list_.push_back(agent_info);
|
||||
}
|
||||
|
||||
// Print the various fields of Hsa Gpu Agents
|
||||
bool HsaRsrcFactory::PrintGpuAgents(const std::string& header) {
|
||||
std::cout << header << " :" << std::endl;
|
||||
|
||||
AgentInfo* agent_info;
|
||||
int size = uint32_t(gpu_list_.size());
|
||||
for (int idx = 0; idx < size; idx++) {
|
||||
agent_info = gpu_list_[idx];
|
||||
|
||||
std::cout << "> agent[" << idx << "] :" << std::endl;
|
||||
std::cout << ">> Name : " << agent_info->name << std::endl;
|
||||
std::cout << ">> Max Wave Size : " << agent_info->max_wave_size << std::endl;
|
||||
std::cout << ">> Max Queue Size : " << agent_info->max_queue_size << std::endl;
|
||||
std::cout << ">> Kernarg Region Id : " << agent_info->coarse_region.handle << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns the file path where brig files is located. Value is
|
||||
// available only after an instance has been built.
|
||||
char* HsaRsrcFactory::GetBrigPath() { return HsaRsrcFactory::brig_path_; }
|
||||
|
||||
// Returns the number of compute units present on platform
|
||||
// Value is available only after an instance has been built.
|
||||
uint32_t HsaRsrcFactory::GetNumOfCUs() { return HsaRsrcFactory::num_cus_; }
|
||||
|
||||
// Returns the maximum number of waves that can be launched
|
||||
// per compute unit. The actual number that can be launched
|
||||
// is affected by resource availability
|
||||
//
|
||||
// Value is available only after an instance has been built.
|
||||
uint32_t HsaRsrcFactory::GetNumOfWavesPerCU() { return HsaRsrcFactory::num_waves_; }
|
||||
|
||||
// Returns the number of work-items that can execute per wave
|
||||
// Value is available only after an instance has been built.
|
||||
uint32_t HsaRsrcFactory::GetNumOfWorkItemsPerWave() { return HsaRsrcFactory::num_workitems_; }
|
||||
|
||||
// Returns the number of times kernel loop body should execute.
|
||||
// Value is available only after an instance has been built.
|
||||
uint32_t HsaRsrcFactory::GetKernelLoopCount() { return HsaRsrcFactory::kernel_loop_count_; }
|
||||
|
||||
// Returns boolean flag to indicate if debug info should be printed
|
||||
// Value is available only after an instance has been built.
|
||||
uint32_t HsaRsrcFactory::GetPrintDebugInfo() { return HsaRsrcFactory::print_debug_info_; }
|
||||
|
||||
// Process command line arguments. The method will capture
|
||||
// various user command line parameters for tests to use
|
||||
void HsaRsrcFactory::ProcessCmdline() {
|
||||
// Command line arguments are given
|
||||
uint32_t idx;
|
||||
uint32_t arg_idx;
|
||||
for (idx = 1; idx < hsa_cmdline_arg_cnt; idx += 2) {
|
||||
arg_idx = GetArgIndex((char*)hsa_cmdline_arg_list[idx]);
|
||||
switch (arg_idx) {
|
||||
case 0:
|
||||
HsaRsrcFactory::brig_path_ = hsa_cmdline_arg_list[idx + 1];
|
||||
break;
|
||||
case 1:
|
||||
HsaRsrcFactory::num_cus_ = atoi(hsa_cmdline_arg_list[idx + 1]);
|
||||
break;
|
||||
case 2:
|
||||
HsaRsrcFactory::num_waves_ = atoi(hsa_cmdline_arg_list[idx + 1]);
|
||||
break;
|
||||
case 3:
|
||||
HsaRsrcFactory::num_workitems_ = atoi(hsa_cmdline_arg_list[idx + 1]);
|
||||
break;
|
||||
case 4:
|
||||
HsaRsrcFactory::kernel_loop_count_ = atoi(hsa_cmdline_arg_list[idx + 1]);
|
||||
break;
|
||||
case 5:
|
||||
HsaRsrcFactory::print_debug_info_ = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t HsaRsrcFactory::GetArgIndex(char* arg_value) {
|
||||
// Map Brig file path to index zero
|
||||
if (!strcmp(HsaRsrcFactory::brig_path_key_, arg_value)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Map Number of Compute Units to index one
|
||||
if (!strcmp(HsaRsrcFactory::num_cus_key_, arg_value)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Map Number of Waves per CU to index two
|
||||
if (!strcmp(HsaRsrcFactory::num_waves_key_, arg_value)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Map Number of Workitems per Wave to index three
|
||||
if (!strcmp(HsaRsrcFactory::num_workitems_key_, arg_value)) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Map Kernel Loop Count to index four
|
||||
if (!strcmp(HsaRsrcFactory::kernel_loop_count_key_, arg_value)) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
// Map print debug info parameter
|
||||
if (!strcmp(HsaRsrcFactory::print_debug_key_, arg_value)) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
return 108;
|
||||
}
|
||||
|
||||
void HsaRsrcFactory::PrintHelpMsg() {
|
||||
std::cout << "Key for passing Brig filepath: " << HsaRsrcFactory::brig_path_key_ << std::endl;
|
||||
std::cout << "Key for passing Number of Compute Units: " << HsaRsrcFactory::num_cus_key_
|
||||
<< std::endl;
|
||||
std::cout << "Key for passing Number of Waves per CU: " << HsaRsrcFactory::num_waves_key_
|
||||
<< std::endl;
|
||||
std::cout << "Key for passing Number of Workitems per Wave: "
|
||||
<< HsaRsrcFactory::num_workitems_key_ << std::endl;
|
||||
std::cout << "Key for passing Kernel Loop Count: " << HsaRsrcFactory::kernel_loop_count_key_
|
||||
<< std::endl;
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
#ifndef HSA_RSRC_FACTORY_H_
|
||||
#define HSA_RSRC_FACTORY_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "perf_timer.h"
|
||||
#include "hsa.h"
|
||||
#include "hsa_ext_finalize.h"
|
||||
|
||||
#define HSA_ARGUMENT_ALIGN_BYTES 16
|
||||
#define HSA_QUEUE_ALIGN_BYTES 64
|
||||
#define HSA_PACKET_ALIGN_BYTES 64
|
||||
|
||||
#define check(msg, status) \
|
||||
if (status != HSA_STATUS_SUCCESS) { \
|
||||
const char* emsg = 0; \
|
||||
hsa_status_string(status, &emsg); \
|
||||
printf("%s: %s\n", msg, emsg ? emsg : "<unknown error>"); \
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
#define check_build(msg, status) \
|
||||
if (status != STATUS_SUCCESS) { \
|
||||
printf("%s\n", msg); \
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
// Provide access to command line arguments passed in by user
|
||||
extern uint32_t hsa_cmdline_arg_cnt;
|
||||
extern char** hsa_cmdline_arg_list;
|
||||
|
||||
// Encapsulates information about a Hsa Agent such as its
|
||||
// handle, name, max queue size, max wavefront size, etc.
|
||||
typedef struct {
|
||||
// Handle of Agent
|
||||
hsa_agent_t dev_id;
|
||||
|
||||
// Agent type - Cpu = 0, Gpu = 1 or Dsp = 2
|
||||
uint32_t dev_type;
|
||||
|
||||
// Name of Agent whose length is less than 64
|
||||
char name[64];
|
||||
|
||||
// Max size of Wavefront size
|
||||
uint32_t max_wave_size;
|
||||
|
||||
// Max size of Queue buffer
|
||||
uint32_t max_queue_size;
|
||||
|
||||
// Hsail profile supported by agent
|
||||
hsa_profile_t profile;
|
||||
|
||||
// Memory region supporting kernel parameters
|
||||
hsa_region_t coarse_region;
|
||||
|
||||
// Memory region supporting kernel arguments
|
||||
hsa_region_t kernarg_region;
|
||||
|
||||
} AgentInfo;
|
||||
|
||||
class HsaRsrcFactory {
|
||||
public:
|
||||
// Constructor of the class. Will initialize the Hsa Runtime and
|
||||
// query the system topology to get the list of Cpu and Gpu devices
|
||||
HsaRsrcFactory();
|
||||
|
||||
// Destructor of the class
|
||||
~HsaRsrcFactory();
|
||||
|
||||
// Get the count of Hsa Gpu Agents available on the platform
|
||||
//
|
||||
// @return uint32_t Number of Gpu agents on platform
|
||||
//
|
||||
uint32_t GetCountOfGpuAgents();
|
||||
|
||||
// Get the count of Hsa Cpu Agents available on the platform
|
||||
//
|
||||
// @return uint32_t Number of Cpu agents on platform
|
||||
//
|
||||
uint32_t GetCountOfCpuAgents();
|
||||
|
||||
// Get the AgentInfo handle of a Gpu device
|
||||
//
|
||||
// @param idx Gpu Agent at specified index
|
||||
//
|
||||
// @param agent_info Output parameter updated with AgentInfo
|
||||
//
|
||||
// @return bool true if successful, false otherwise
|
||||
//
|
||||
bool GetGpuAgentInfo(uint32_t idx, AgentInfo** agent_info);
|
||||
|
||||
// Get the AgentInfo handle of a Cpu device
|
||||
//
|
||||
// @param idx Cpu Agent at specified index
|
||||
//
|
||||
// @param agent_info Output parameter updated with AgentInfo
|
||||
//
|
||||
// @return bool true if successful, false otherwise
|
||||
//
|
||||
bool GetCpuAgentInfo(uint32_t idx, AgentInfo** agent_info);
|
||||
|
||||
// Create a Queue object and return its handle. The queue object is expected
|
||||
// to support user requested number of Aql dispatch packets.
|
||||
//
|
||||
// @param agent_info Gpu Agent on which to create a queue object
|
||||
//
|
||||
// @param num_Pkts Number of packets to be held by queue
|
||||
//
|
||||
// @param queue Output parameter updated with handle of queue object
|
||||
//
|
||||
// @return bool true if successful, false otherwise
|
||||
//
|
||||
bool CreateQueue(AgentInfo* agent_info, uint32_t num_pkts, hsa_queue_t** queue);
|
||||
|
||||
// Create a Signal object and return its handle.
|
||||
//
|
||||
// @param value Initial value of signal object
|
||||
//
|
||||
// @param signal Output parameter updated with handle of signal object
|
||||
//
|
||||
// @return bool true if successful, false otherwise
|
||||
//
|
||||
bool CreateSignal(uint32_t value, hsa_signal_t* signal);
|
||||
|
||||
// Allocate memory for use by a kernel of specified size in specified
|
||||
// agent's memory region. Currently supports Global segment whose Kernarg
|
||||
// flag set.
|
||||
//
|
||||
// @param agent_info Agent from whose memory region to allocate
|
||||
//
|
||||
// @param size Size of memory in terms of bytes
|
||||
//
|
||||
// @return uint8_t* Pointer to buffer, null if allocation fails.
|
||||
//
|
||||
uint8_t* AllocateLocalMemory(AgentInfo* agent_info, size_t size);
|
||||
uint8_t* AllocateMemory(AgentInfo* agent_info, size_t size);
|
||||
|
||||
bool TransferData(uint8_t* dest_buff, uint8_t* src_buff, uint32_t length, bool host_to_dev);
|
||||
|
||||
// Allocate memory tp pass kernel parameters.
|
||||
//
|
||||
// @param agent_info Agent from whose memory region to allocate
|
||||
//
|
||||
// @param size Size of memory in terms of bytes
|
||||
//
|
||||
// @return uint8_t* Pointer to buffer, null if allocation fails.
|
||||
//
|
||||
uint8_t* AllocateSysMemory(AgentInfo* agent_info, size_t size);
|
||||
|
||||
// Loads an Assembled Brig file and Finalizes it into Device Isa
|
||||
//
|
||||
// @param agent_info Gpu device for which to finalize
|
||||
//
|
||||
// @param brig_path File path of the Assembled Brig file
|
||||
//
|
||||
// @param kernel_name Name of the kernel to finalize
|
||||
//
|
||||
// @param code_desc Handle of finalized Code Descriptor that could
|
||||
// be used to submit for execution
|
||||
//
|
||||
// @return bool true if successful, false otherwise
|
||||
//
|
||||
bool LoadAndFinalize(AgentInfo* agent_info, const char* brig_path, char* kernel_name,
|
||||
hsa_executable_symbol_t* code_desc);
|
||||
|
||||
// Add an instance of AgentInfo representing a Hsa Gpu agent
|
||||
void AddAgentInfo(AgentInfo* agent_info, bool gpu);
|
||||
|
||||
// Returns the file path where brig files is located
|
||||
static char* GetBrigPath();
|
||||
|
||||
// Returns the number of compute units present on platform
|
||||
static uint32_t GetNumOfCUs();
|
||||
|
||||
// Returns the maximum number of waves that can be launched
|
||||
// per compute unit. The actual number that can be launched
|
||||
// is affected by resource availability
|
||||
static uint32_t GetNumOfWavesPerCU();
|
||||
|
||||
// Returns the number of work-items that can execute per wave
|
||||
static uint32_t GetNumOfWorkItemsPerWave();
|
||||
|
||||
// Returns the number of times kernel loop body should execute.
|
||||
static uint32_t GetKernelLoopCount();
|
||||
|
||||
// Returns boolean flag to indicate if debug info should be printed
|
||||
static uint32_t GetPrintDebugInfo();
|
||||
|
||||
// Print the various fields of Hsa Gpu Agents
|
||||
bool PrintGpuAgents(const std::string& header);
|
||||
|
||||
private:
|
||||
// Number of queues to create
|
||||
uint32_t num_queues_;
|
||||
|
||||
// Used to maintain a list of Hsa Queue handles
|
||||
std::vector<hsa_queue_t*> queue_list_;
|
||||
|
||||
// Number of Signals to create
|
||||
uint32_t num_signals_;
|
||||
|
||||
// Used to maintain a list of Hsa Signal handles
|
||||
std::vector<hsa_signal_t*> signal_list_;
|
||||
|
||||
// Number of agents reported by platform
|
||||
uint32_t num_agents_;
|
||||
|
||||
// Used to maintain a list of Hsa Gpu Agent Info
|
||||
std::vector<AgentInfo*> gpu_list_;
|
||||
|
||||
// Used to maintain a list of Hsa Cpu Agent Info
|
||||
std::vector<AgentInfo*> cpu_list_;
|
||||
|
||||
// Records the file path where Brig file is located.
|
||||
// Value is available only after an instance has been built.
|
||||
static char* brig_path_;
|
||||
static char* brig_path_key_;
|
||||
|
||||
// Records the number of Compute units present on system.
|
||||
// Value is available only after an instance has been built.
|
||||
static uint32_t num_cus_;
|
||||
static char* num_cus_key_;
|
||||
|
||||
// Records the number of waves that can be launched per Compute unit
|
||||
// Value is available only after an instance has been built.
|
||||
static uint32_t num_waves_;
|
||||
static char* num_waves_key_;
|
||||
|
||||
// Records the number of work-items that can be packed into a wave
|
||||
// Value is available only after an instance has been built.
|
||||
static uint32_t num_workitems_;
|
||||
static char* num_workitems_key_;
|
||||
|
||||
// Records the number of times kernel loop body should run. Value
|
||||
// is available only after an instance has been built.
|
||||
static uint32_t kernel_loop_count_;
|
||||
static char* kernel_loop_count_key_;
|
||||
|
||||
// Records the number of times kernel loop body should run. Value
|
||||
// is available only after an instance has been built.
|
||||
static bool print_debug_info_;
|
||||
static char* print_debug_key_;
|
||||
|
||||
// Process command line arguments. The method will capture
|
||||
// various user command line parameters for tests to use
|
||||
static void ProcessCmdline();
|
||||
|
||||
// Prints the help banner on user arg keys
|
||||
static void PrintHelpMsg();
|
||||
|
||||
// Maps an index for the user argument
|
||||
static uint32_t GetArgIndex(char* arg_value);
|
||||
};
|
||||
|
||||
#endif // HSA_RSRC_FACTORY_H_
|
||||
@@ -0,0 +1,157 @@
|
||||
#include "perf_timer.h"
|
||||
|
||||
PerfTimer::PerfTimer() { freq_in_100mhz = MeasureTSCFreqHz(); }
|
||||
|
||||
PerfTimer::~PerfTimer() {
|
||||
while (!_timers.empty()) {
|
||||
Timer* temp = _timers.back();
|
||||
_timers.pop_back();
|
||||
delete temp;
|
||||
}
|
||||
}
|
||||
|
||||
// a new cretaed timer instantance index will be returned
|
||||
int PerfTimer::CreateTimer() {
|
||||
Timer* newTimer = new Timer;
|
||||
newTimer->_start = 0;
|
||||
newTimer->_clocks = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&newTimer->_freq);
|
||||
#else
|
||||
newTimer->_freq = (long long)1.0E3;
|
||||
#endif
|
||||
|
||||
/* Push back the address of new Timer instance created */
|
||||
_timers.push_back(newTimer);
|
||||
return (int)(_timers.size() - 1);
|
||||
}
|
||||
|
||||
int PerfTimer::StartTimer(int index) {
|
||||
if (index >= (int)_timers.size()) {
|
||||
Error("Cannot reset timer. Invalid handle.");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// General Windows timing method
|
||||
#ifndef _AMD
|
||||
long long tmpStart;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&(tmpStart));
|
||||
_timers[index]->_start = (double)tmpStart;
|
||||
#else
|
||||
// AMD Windows timing method
|
||||
#endif
|
||||
#else
|
||||
// General Linux timing method
|
||||
#ifndef _AMD
|
||||
struct timeval s;
|
||||
gettimeofday(&s, 0);
|
||||
_timers[index]->_start = s.tv_sec * 1.0E3 + ((double)(s.tv_usec / 1.0E3));
|
||||
#else
|
||||
// AMD timing method
|
||||
unsigned int unused;
|
||||
_timers[index]->_start = __rdtscp(&unused);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int PerfTimer::StopTimer(int index) {
|
||||
double n = 0;
|
||||
if (index >= (int)_timers.size()) {
|
||||
Error("Cannot reset timer. Invalid handle.");
|
||||
return FAILURE;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
#ifndef _AMD
|
||||
long long n1;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&(n1));
|
||||
n = (double)n1;
|
||||
#else
|
||||
// AMD Window Timing
|
||||
#endif
|
||||
|
||||
#else
|
||||
// General Linux timing method
|
||||
#ifndef _AMD
|
||||
struct timeval s;
|
||||
gettimeofday(&s, 0);
|
||||
n = s.tv_sec * 1.0E3 + (double)(s.tv_usec / 1.0E3);
|
||||
#else
|
||||
// AMD Linux timing
|
||||
unsigned int unused;
|
||||
n = __rdtscp(&unused);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
n -= _timers[index]->_start;
|
||||
_timers[index]->_start = 0;
|
||||
|
||||
#ifndef _AMD
|
||||
_timers[index]->_clocks += n;
|
||||
#else
|
||||
//_timers[index]->_clocks += 10 * n /freq_in_100mhz; // unit is ns
|
||||
_timers[index]->_clocks += 1.0E-6 * 10 * n / freq_in_100mhz; // convert to ms
|
||||
#endif
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void PerfTimer::Error(string str) { cout << str << endl; }
|
||||
|
||||
|
||||
double PerfTimer::ReadTimer(int index) {
|
||||
if (index >= (int)_timers.size()) {
|
||||
Error("Cannot read timer. Invalid handle.");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
double reading = double(_timers[index]->_clocks);
|
||||
|
||||
reading = double(reading / _timers[index]->_freq);
|
||||
|
||||
return reading;
|
||||
}
|
||||
|
||||
|
||||
uint64_t PerfTimer::CoarseTimestampUs() {
|
||||
#ifdef _WIN32
|
||||
uint64_t freqHz, ticks;
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&freqHz);
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&ticks);
|
||||
|
||||
// Scale numerator and divisor until (ticks * 1000000) fits in uint64_t.
|
||||
while (ticks > (1ULL << 44)) {
|
||||
ticks /= 16;
|
||||
freqHz /= 16;
|
||||
}
|
||||
|
||||
return (ticks * 1000000) / freqHz;
|
||||
#else
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||
return uint64_t(ts.tv_sec) * 1000000 + ts.tv_nsec / 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t PerfTimer::MeasureTSCFreqHz() {
|
||||
// Make a coarse interval measurement of TSC ticks for 1 gigacycles.
|
||||
unsigned int unused;
|
||||
uint64_t tscTicksEnd;
|
||||
|
||||
uint64_t coarseBeginUs = CoarseTimestampUs();
|
||||
uint64_t tscTicksBegin = __rdtscp(&unused);
|
||||
do {
|
||||
tscTicksEnd = __rdtscp(&unused);
|
||||
} while (tscTicksEnd - tscTicksBegin < 1000000000);
|
||||
|
||||
uint64_t coarseEndUs = CoarseTimestampUs();
|
||||
|
||||
// Compute the TSC frequency and round to nearest 100MHz.
|
||||
uint64_t coarseIntervalNs = (coarseEndUs - coarseBeginUs) * 1000;
|
||||
uint64_t tscIntervalTicks = tscTicksEnd - tscTicksBegin;
|
||||
return (tscIntervalTicks * 10 + (coarseIntervalNs / 2)) / coarseIntervalNs;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef _PERF_TIMER_H_
|
||||
#define _PERF_TIMER_H_
|
||||
|
||||
// Will use AMD timer and general Linux timer based on users' need --> compilation flag
|
||||
// need to consider platform is Windows or Linux
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#if defined(_MSC_VER)
|
||||
#include <time.h>
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
#else
|
||||
#if defined(__GNUC__)
|
||||
#include <sys/time.h>
|
||||
#include <x86intrin.h>
|
||||
#endif // __GNUC__
|
||||
#endif //_MSC_VER
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PerfTimer {
|
||||
public:
|
||||
enum { SUCCESS = 0, FAILURE = 1 };
|
||||
|
||||
PerfTimer();
|
||||
~PerfTimer();
|
||||
|
||||
// General Linux timing method
|
||||
int CreateTimer();
|
||||
int StartTimer(int index);
|
||||
int StopTimer(int index);
|
||||
|
||||
// retrieve time
|
||||
double ReadTimer(int index);
|
||||
// write into a file
|
||||
double WriteTimer(int index);
|
||||
|
||||
private:
|
||||
struct Timer {
|
||||
string name; /* < name name of time object*/
|
||||
long long _freq; /* < _freq frequency*/
|
||||
double _clocks; /* < _clocks number of ticks at end*/
|
||||
double _start; /* < _start start point ticks*/
|
||||
};
|
||||
|
||||
std::vector<Timer*> _timers; /*< _timers vector to Timer objects */
|
||||
double freq_in_100mhz;
|
||||
|
||||
// AMD timing method
|
||||
uint64_t CoarseTimestampUs();
|
||||
uint64_t MeasureTSCFreqHz();
|
||||
|
||||
void Error(string str);
|
||||
};
|
||||
|
||||
#endif // _PERF_TIMER_H_
|
||||
새 이슈에서 참조
사용자 차단