ROC profiler prototype sources importing

이 커밋은 다음에 포함됨:
Evgeny
2017-11-09 17:26:19 -06:00
부모 54156e1953
커밋 85278f08a0
63개의 변경된 파일과 7598개의 추가작업 그리고 0개의 파일을 삭제
+14
파일 보기
@@ -0,0 +1,14 @@
#
# Build dynamic Library object
#
set ( TARGET_LIB "${TARGET_NAME}" )
set ( LIB_SRC
${LIB_DIR}/core/rocprofiler.cpp
${LIB_DIR}/core/proxy_queue.cpp
${LIB_DIR}/core/simple_proxy_queue.cpp
${LIB_DIR}/core/intercept_queue.cpp
${LIB_DIR}/util/hsa_rsrc_factory.cpp
)
add_library ( ${TARGET_LIB} SHARED ${LIB_SRC} )
target_include_directories ( ${TARGET_LIB} PRIVATE ${LIB_DIR} ${ROOT_DIR} ${HSA_RUNTIME_INC_PATH} )
target_link_libraries( ${TARGET_LIB} PRIVATE ${HSA_RUNTIME_LIB} c stdc++)
+399
파일 보기
@@ -0,0 +1,399 @@
#ifndef SRC_CORE_CONTEXT_H_
#define SRC_CORE_CONTEXT_H_
#include "inc/rocprofiler.h"
#include <hsa.h>
#include <map>
#include <vector>
#include "core/metrics.h"
#include "core/profile.h"
#include "core/queue.h"
#include "core/types.h"
#include "util/exception.h"
#include "util/hsa_rsrc_factory.h"
namespace rocprofiler {
struct rocprofiler_contex_t;
class Context;
inline unsigned align_size(unsigned size, unsigned alignment) { return ((size + alignment - 1) & ~(alignment - 1)); }
// Block descriptor
struct block_des_t {
uint32_t id;
uint32_t index;
};
// block_des_t less-then functor
struct lt_block_des {
bool operator()(const block_des_t& a1, const block_des_t& a2) const {
return (a1.id < a2.id) || ((a1.id == a2.id) && (a1.index < a2.index));
}
};
// Block status
struct block_status_t {
uint32_t max_counters;
uint32_t counter_index;
uint32_t group_index;
};
// Metrics arguments
template <class Map>
class MetricArgs : public xml::args_cache_t {
public:
MetricArgs(const Map& map) : map_(map) {}
bool Lookup(const std::string& name, uint64_t& result) const {
rocprofiler_info_t* info = NULL;
auto it = map_.find(name);
if (it == map_.end()) EXC_RAISING(HSA_STATUS_ERROR, "var '" << name << "' is not found");
info = it->second;
if (info) {
result = info->data.result_int64;
if (info->data.kind == ROCPROFILER_UNINIT) EXC_RAISING(HSA_STATUS_ERROR, "var '" << name << "' is uninitialized");
if (info->data.kind != ROCPROFILER_INT64) EXC_RAISING(HSA_STATUS_ERROR, "var '" << name << "' is of incompatible type, not INT64");
} else EXC_RAISING(HSA_STATUS_ERROR, "var '" << name << "' info is NULL");
return (info != NULL);
}
private:
const Map& map_;
};
// Profiling group
class Group {
public:
Group(const util::AgentInfo* agent_info, Context *context, const uint32_t& index) :
pmc_profile_(agent_info),
sqtt_profile_(agent_info),
context_(context),
index_(index)
{}
void Insert(const profile_info_t& info) {
const rocprofiler_type_t type = info.rinfo->type;
info_vector_.push_back(info.rinfo);
switch (type) {
case ROCPROFILER_TYPE_METRIC:
pmc_profile_.Insert(info);
break;
case ROCPROFILER_TYPE_TRACE:
sqtt_profile_.Insert(info);
break;
default:
EXC_RAISING(HSA_STATUS_ERROR, "bad rocprofiler type (" << type << ")");
}
}
hsa_status_t Finalize() {
hsa_status_t status = pmc_profile_.Finalize(start_vector_, stop_vector_);
if (status == HSA_STATUS_SUCCESS) {
status = sqtt_profile_.Finalize(start_vector_, stop_vector_);
}
return status;
}
void GetProfiles(profile_vector_t& vec) {
pmc_profile_.GetProfiles(vec);
sqtt_profile_.GetProfiles(vec);
}
void GetTraceProfiles(profile_vector_t& vec) {
sqtt_profile_.GetProfiles(vec);
}
info_vector_t& GetInfoVector() { return info_vector_; }
const pkt_vector_t& GetStartVector() const { return start_vector_; }
const pkt_vector_t& GetStopVector() const { return stop_vector_; }
Context* GetContext() { return context_; }
uint32_t GetIndex() const { return index_; }
private:
PmcProfile pmc_profile_;
SqttProfile sqtt_profile_;
info_vector_t info_vector_;
pkt_vector_t start_vector_;
pkt_vector_t stop_vector_;
Context* const context_;
const uint32_t index_;
};
// Profiling context
class Context {
public:
typedef std::map<std::string, rocprofiler_info_t*> info_map_t;
Context(const util::AgentInfo* agent_info, Queue* queue, rocprofiler_info_t* info, const uint32_t info_count) :
agent_(agent_info->dev_id),
agent_info_(agent_info),
queue_(queue),
hsa_rsrc_(&util::HsaRsrcFactory::Instance()),
api_(hsa_rsrc_->AqlProfileApi()),
metrics_(agent_info)
{
Initialize(info, info_count);
Finalize();
}
~Context() {
for (const auto& v : info_map_) {
const std::string& name = v.first;
const rocprofiler_info_t* info = v.second;
if ((info->type == ROCPROFILER_TYPE_METRIC) && (metrics_map_.find(name) == metrics_map_.end())) {
delete info;
}
}
}
void Initialize(rocprofiler_info_t* info_array, const uint32_t info_count) {
info_map_t input_map;
for (unsigned i = 0; i < info_count; ++i) {
rocprofiler_info_t* info = &info_array[i];
input_map[info->name] = info;
info->data.kind = ROCPROFILER_UNINIT;
}
if (info_count) set_.push_back(Group(agent_info_, this, 0));
for (unsigned i = 0; i < info_count; ++i) {
rocprofiler_info_t* info = &info_array[i];
info_map_[info->name] = info;
const rocprofiler_type_t type = info->type;
const char* name = info->name;
if (type == ROCPROFILER_TYPE_METRIC) {
const Metric* metric = metrics_.Get(name);
if (metric == NULL) EXC_RAISING(HSA_STATUS_ERROR, "metric '" << name << "' is not found");
auto ret = metrics_map_.insert({name, metric});
if (!ret.second) EXC_RAISING(HSA_STATUS_ERROR, "metric '" << name << "' is registered more then once");
counters_vec_t counters_vec = metric->GetCounters();
if (counters_vec.empty()) EXC_RAISING(HSA_STATUS_ERROR, "metric name '" << name << "' is not found");
for (const counter_t* counter : counters_vec) {
if (metric->GetExpr()) {
auto it = input_map.find(counter->name);
if (it != input_map.end()) {
continue;
} else {
info = NewCounterInfo(counter);
info_map_[info->name] = info;
}
}
const event_t* event = &(counter->event);
const block_des_t block_des = {event->block_name, event->block_index};
auto ret = groups_map_.insert({block_des, {}});
block_status_t& block_status = ret.first->second;
if (block_status.max_counters == 0) {
profile_t query = {};
query.agent = agent_;
query.type = HSA_VEN_AMD_AQLPROFILE_EVENT_TYPE_PMC;
query.events = event;
uint32_t block_counters;
hsa_status_t status = api_->hsa_ven_amd_aqlprofile_get_info(&query, HSA_VEN_AMD_AQLPROFILE_INFO_BLOCK_COUNTERS, &block_counters);
if (status != HSA_STATUS_SUCCESS) AQL_EXC_RAISING(status, "get block_counters info");
block_status.max_counters = block_counters;
}
if (block_status.counter_index >= block_status.max_counters) {
block_status.counter_index = 0;
block_status.group_index += 1;
}
if (block_status.group_index >= set_.size()) {
set_.push_back(Group(agent_info_, this, block_status.group_index));
}
const uint32_t group_index = block_status.group_index;
set_[group_index].Insert(profile_info_t{event, NULL, 0, info});
}
} else if (type == ROCPROFILER_TYPE_TRACE) {
set_[0].Insert(profile_info_t{NULL, info->parameters, info->parameter_count, info});
} else {
EXC_RAISING(HSA_STATUS_ERROR, "bad rocprofiler type (" << type << ")");
}
}
}
void Finalize() {
for (unsigned index = 0; index < set_.size(); ++index) {
const hsa_status_t status = set_[index].Finalize();
if (status != HSA_STATUS_SUCCESS) EXC_RAISING(status, "context finalize failed");
}
}
uint32_t GetGroupCount() const { return set_.size(); }
rocprofiler_group_t GetGroupInfo(const uint32_t& index) {
rocprofiler::info_vector_t& info_vector = set_[index].GetInfoVector();
rocprofiler_group_t group = {};
group.info_count = info_vector.size();
group.info = &info_vector[0];
group.context = reinterpret_cast<rocprofiler_t*>(this);
group.index = index;
return group;
}
const pkt_vector_t& StartPackets(const uint32_t& group_index) const { return set_[group_index].GetStartVector(); }
const pkt_vector_t& StopPackets(const uint32_t& group_index) const { return set_[group_index].GetStopVector(); }
void Start(const uint32_t& group_index, Queue* const queue = NULL) {
const pkt_vector_t& start_packets = StartPackets(group_index);
Queue* const submit_queue = (queue != NULL) ? queue : queue_;
submit_queue->Submit(&start_packets[0], start_packets.size());
}
void Stop(const uint32_t& group_index, Queue* const queue = NULL) {
const pkt_vector_t& stop_packets = StopPackets(group_index);
Queue* const submit_queue = (queue != NULL) ? queue : queue_;
submit_queue->Submit(&stop_packets[0], stop_packets.size());
}
void Submit(const uint32_t& group_index, const packet_t* packet, Queue* const queue = NULL) {
Queue* const submit_queue = (queue != NULL) ? queue : queue_;
Start(group_index, submit_queue);
submit_queue->Submit(packet);
Stop(group_index, submit_queue);
}
struct callback_data_t {
info_vector_t* info_vector;
size_t index;
char* ptr;
};
void GetData(const uint32_t& group_index) {
const profile_vector_t profile_vector = GetProfiles(group_index);
for (auto& tuple : profile_vector) {
// Wait for stop packet to complete
hsa_signal_wait_scacquire(
tuple.completion_signal,
HSA_SIGNAL_CONDITION_LT,
1,
(uint64_t)-1,
HSA_WAIT_STATE_BLOCKED);
callback_data_t callback_data{tuple.info_vector, tuple.info_vector->size(), NULL};
const hsa_status_t status = api_->hsa_ven_amd_aqlprofile_iterate_data(tuple.profile, DataCallback, &callback_data);
if (status != HSA_STATUS_SUCCESS) AQL_EXC_RAISING(status, "context iterate data failed");
}
}
void GetMetricsData() const {
const MetricArgs<info_map_t> args(info_map_);
for (const auto v : metrics_map_) {
const std::string& name = v.first;
const Metric* metric = v.second;
const xml::Expr* expr = metric->GetExpr();
if (expr) {
auto it = info_map_.find(name);
if (it == info_map_.end()) EXC_RAISING(HSA_STATUS_ERROR, "metric '" << name << "', rocprofiler info is not found");
rocprofiler_info_t* info = it->second;
info->data.result_int64 = expr->Eval(args);
info->data.kind = ROCPROFILER_INT64;
}
}
}
void IterateTraceData(rocprofiler_trace_data_callback_t callback, void *data) {
profile_vector_t profile_vector;
set_[0].GetTraceProfiles(profile_vector);
for (auto& tuple : profile_vector) {
const hsa_status_t status = api_->hsa_ven_amd_aqlprofile_iterate_data(tuple.profile, callback, data);
if (status != HSA_STATUS_SUCCESS) AQL_EXC_RAISING(status, "context iterate data failed");
}
}
private:
// Getting profling packets
profile_vector_t GetProfiles(const uint32_t& index) {
profile_vector_t vec;
if (index >= set_.size()) {
EXC_RAISING(HSA_STATUS_ERROR, "index exceeding the maximum " << set_.size());
}
set_[index].GetProfiles(vec);
return vec;
}
static hsa_status_t DataCallback(hsa_ven_amd_aqlprofile_info_type_t ainfo_type,
hsa_ven_amd_aqlprofile_info_data_t* ainfo_data,
void* data) {
hsa_status_t status = HSA_STATUS_SUCCESS;
callback_data_t* callback_data = reinterpret_cast<callback_data_t*>(data);
info_vector_t& info_vector = *(callback_data->info_vector);
uint32_t index = callback_data->index;
const uint32_t sample_id = ainfo_data->sample_id;
if (info_vector.size() == index) {
index = 0;
} else {
if (sample_id == 0) index += 1;
}
callback_data->index = index;
if (index < info_vector.size()) {
rocprofiler_info_t* rinfo = info_vector[index];
if (ainfo_type == HSA_VEN_AMD_AQLPROFILE_INFO_PMC_DATA) {
if (ainfo_data->sample_id == 0) rinfo->data.result_int64 = 0;
rinfo->data.result_int64 += ainfo_data->pmc_data.result;
rinfo->data.kind = ROCPROFILER_INT64;
} else if (ainfo_type == HSA_VEN_AMD_AQLPROFILE_INFO_SQTT_DATA) {
if (rinfo->data.result_bytes.copy) {
char* result_bytes_ptr = reinterpret_cast<char*>(rinfo->data.result_bytes.ptr);
const char* end = result_bytes_ptr + rinfo->data.result_bytes.size;
const char* src = reinterpret_cast<char*>(ainfo_data->sqtt_data.ptr);
const uint32_t size = ainfo_data->sqtt_data.size;
char* ptr = (sample_id == 0) ? result_bytes_ptr : callback_data->ptr;
uint64_t* header = reinterpret_cast<uint64_t*>(ptr);
char* dest = ptr + sizeof(*header);
if ((dest + size) < end) {
hsa_status_t status = hsa_memory_copy(dest, src, size);
if (status == HSA_STATUS_SUCCESS) {
*header = size;
rinfo->data.kind = ROCPROFILER_BYTES;
rinfo->data.result_bytes.instance_count = sample_id + 1;
callback_data->ptr = dest + align_size(size, sizeof(uint64_t));
}
} else status = HSA_STATUS_ERROR;
} else {
if (sample_id == 0) {
rinfo->data.kind = ROCPROFILER_BYTES;
rinfo->data.result_bytes.ptr = ainfo_data->sqtt_data.ptr;
rinfo->data.result_bytes.instance_count = UINT32_MAX;
}
rinfo->data.result_bytes.instance_count += 1;
}
} else status = HSA_STATUS_ERROR;
} else status = HSA_STATUS_ERROR;
return status;
}
rocprofiler_info_t* NewCounterInfo(const counter_t* counter) {
rocprofiler_info_t* info = new rocprofiler_info_t{};
info->type = ROCPROFILER_TYPE_METRIC;
info->name = counter->name.c_str();
return info;
}
// GPU handel
const hsa_agent_t agent_;
const util::AgentInfo* agent_info_;
// Profiling queue
Queue* queue_;
// HSA resources factory
util::HsaRsrcFactory* hsa_rsrc_;
// aqlprofile API table
const pfn_t* api_;
// Profile group set
std::vector<Group> set_;
// Metrics dictionary
MetricsDict metrics_;
// Groups map
std::map<block_des_t, block_status_t, lt_block_des> groups_map_;
// Info map
info_map_t info_map_;
// Metrics map
std::map<std::string, const Metric*> metrics_map_;
};
} // namespace rocprofiler
#endif // SRC_CORE_CONTEXT_H_
+49
파일 보기
@@ -0,0 +1,49 @@
#ifndef _SRC_CORE_HSA_PROXY_QUEUE_H
#define _SRC_CORE_HSA_PROXY_QUEUE_H
#include <hsa.h>
#include <atomic>
#include <map>
#include <mutex>
#include "core/proxy_queue.h"
#include "util/exception.h"
namespace rocprofiler {
extern decltype(hsa_queue_destroy)* hsa_queue_destroy_fn;
extern decltype(hsa_amd_queue_intercept_create)* hsa_amd_queue_intercept_create_fn;
extern decltype(hsa_amd_queue_intercept_register)* hsa_amd_queue_intercept_register_fn;
class HsaProxyQueue : public ProxyQueue {
public:
hsa_status_t SetInterceptCB(on_submit_cb_t on_submit_cb, void* data) {
return hsa_amd_queue_intercept_register_fn(queue_, on_submit_cb, data);
}
void Submit(const packet_t* packet) { EXC_RAISING(HSA_STATUS_ERROR, "HsaProxyQueue::Submit() is not supported"); }
private:
hsa_status_t Init(
hsa_agent_t agent,
uint32_t size,
hsa_queue_type32_t type,
void (*callback)(hsa_status_t status, hsa_queue_t *source, void *data),
void *data,
uint32_t private_segment_size,
uint32_t group_segment_size,
hsa_queue_t **queue)
{
printf("HsaProxyQueue::Init()\n");
const auto status = hsa_amd_queue_intercept_create_fn(agent, size, type, callback, data, private_segment_size, group_segment_size, &queue_);
*queue = queue_;
return status;
}
hsa_status_t Cleanup() const { return hsa_queue_destroy_fn(queue_); }
hsa_queue_t* queue_;
};
} // namespace rocprofiler
#endif // _SRC_CORE_HSA_PROXY_QUEUE_H
+60
파일 보기
@@ -0,0 +1,60 @@
#ifndef _SRC_CORE_HSA_QUEUE_H
#define _SRC_CORE_HSA_QUEUE_H
#include <atomic>
#include "core/queue.h"
#include "core/types.h"
namespace rocprofiler {
class HsaQueue : public Queue {
public:
typedef void (HsaQueue::*submit_fptr_t)(const packet_t* packet);
enum {
LEGACY_SLOT_SIZE_W = HSA_VEN_AMD_AQLPROFILE_LEGACY_PM4_PACKET_SIZE / sizeof(packet_word_t),
LEGACY_SLOT_SIZE_P = HSA_VEN_AMD_AQLPROFILE_LEGACY_PM4_PACKET_SIZE / sizeof(packet_t)
};
struct slot_pm4_t {
packet_word_t words[LEGACY_SLOT_SIZE_W];
};
HsaQueue(const util::AgentInfo* agent_info, hsa_queue_t* queue) :
queue_(queue)
{}
void Submit(const packet_t* packet) {
// Compute the write index of queue and copy Aql packet into it
const uint64_t que_idx = hsa_queue_load_write_index_relaxed(queue_);
// Increment the write index
hsa_queue_store_write_index_relaxed(queue_, que_idx + 1);
const uint32_t mask = queue_->size - 1;
// Copy packet to the queue
const packet_word_t* src = reinterpret_cast<const packet_word_t*>(packet);
packet_t* slot = reinterpret_cast<packet_t*>(queue_->base_address) + (que_idx & mask);
packet_word_t* dst = reinterpret_cast<packet_word_t*>(slot);
const uint32_t nwords = sizeof(packet_t) / sizeof(packet_word_t);
for (unsigned i = 1; i < nwords; ++i) {
dst[i] = src[i];
}
// To maintain global order to ensure the prior copy of the packet contents is made visible
// before the header is updated.
// With in-order CP it will wait until the first packet in the blob will be valid
std::atomic<packet_word_t>* header_atomic_ptr =
reinterpret_cast<std::atomic<packet_word_t>*>(&dst[0]);
header_atomic_ptr->store(src[0], std::memory_order_release);
// Doorbell signaling
hsa_signal_store_relaxed(queue_->doorbell_signal, que_idx);
}
private:
hsa_queue_t* queue_;
};
} // namespace rocprofiler
#endif // _SRC_CORE_HSA_QUEUE_H
+15
파일 보기
@@ -0,0 +1,15 @@
#include "core/intercept_queue.h"
namespace rocprofiler {
void InterceptQueue::HsaIntercept(HsaApiTable* table) {
table->core_->hsa_queue_create_fn = rocprofiler::InterceptQueue::QueueCreate;
table->core_->hsa_queue_destroy_fn = rocprofiler::InterceptQueue::QueueDestroy;
}
InterceptQueue::mutex_t InterceptQueue::mutex_;
rocprofiler_callback_t InterceptQueue::on_dispatch_cb_ = NULL;
void* InterceptQueue::on_dispatch_cb_data_ = NULL;
const char* InterceptQueue::tool_lib_ = NULL;
void* InterceptQueue::tool_handle_ = NULL;
InterceptQueue::obj_map_t* InterceptQueue::obj_map_ = NULL;
} // namespace rocprofiler
+161
파일 보기
@@ -0,0 +1,161 @@
#ifndef _SRC_CORE_INTERCEPT_QUEUE_H
#define _SRC_CORE_INTERCEPT_QUEUE_H
#include <dlfcn.h>
#include <atomic>
#include <iostream>
#include <map>
#include <mutex>
#include "core/context.h"
#include "core/proxy_queue.h"
#include "core/types.h"
#include "util/hsa_rsrc_factory.h"
namespace rocprofiler {
extern decltype(hsa_queue_create)* hsa_queue_create_fn;
extern decltype(hsa_queue_destroy)* hsa_queue_destroy_fn;
class InterceptQueue {
public:
typedef std::recursive_mutex mutex_t;
typedef std::map<uint64_t, InterceptQueue*> obj_map_t;
static void HsaIntercept(HsaApiTable* table);
static void SetTool(const char* tool) { tool_lib_ = tool; }
static void UnloadTool() { if (tool_handle_) dlclose(tool_handle_); }
static hsa_status_t QueueCreate(
hsa_agent_t agent,
uint32_t size,
hsa_queue_type32_t type,
void (*callback)(hsa_status_t status, hsa_queue_t *source, void *data),
void *data,
uint32_t private_segment_size,
uint32_t group_segment_size,
hsa_queue_t **queue)
{
std::lock_guard<mutex_t> lck(mutex_);
hsa_status_t status = HSA_STATUS_ERROR;
if (tool_lib_) {
tool_handle_ = dlopen(tool_lib_, RTLD_NOW);
if (tool_handle_ == NULL) {
fprintf(stderr, "ROCProfiler: can't load tool library \"%s\"\n", tool_lib_);
fprintf(stderr, "%s\n", dlerror());
exit(1);
}
tool_lib_ = NULL;
}
if (!obj_map_) obj_map_ = new obj_map_t;
ProxyQueue* proxy = ProxyQueue::Create(agent, size, type, callback, data, private_segment_size, group_segment_size, queue, &status);
if (status != HSA_STATUS_SUCCESS) {
InterceptQueue* obj = new InterceptQueue(agent, proxy);
(*obj_map_)[(uint64_t)(*queue)] = obj;
status = proxy->SetInterceptCB(OnSubmitCB, obj);
}
return status;
}
static hsa_status_t QueueDestroy(hsa_queue_t *queue) {
std::lock_guard<mutex_t> lck(mutex_);
hsa_status_t status = HSA_STATUS_ERROR;
obj_map_t::iterator it = obj_map_->find((uint64_t)queue);
if (it != obj_map_->end()) {
const InterceptQueue* obj = it->second;
delete obj;
obj_map_->erase(it);
status = HSA_STATUS_SUCCESS;
}
return status;
}
static void OnSubmitCB(const void* in_packets, uint64_t count, uint64_t user_que_idx, void* data, hsa_amd_queue_intercept_packet_writer writer) {
const packet_t* packets_arr = reinterpret_cast<const packet_t*>(in_packets);
InterceptQueue* obj = reinterpret_cast<InterceptQueue*>(data);
Queue* proxy = obj->proxy_;
for (uint64_t j = 0; j < count; ++j) {
bool to_submit = true;
const packet_t* packet = &packets_arr[j];
if ((GetHeaderType(packet) == HSA_PACKET_TYPE_KERNEL_DISPATCH) && (on_dispatch_cb_ != NULL)) {
rocprofiler_group_t* group = NULL;
const hsa_kernel_dispatch_packet_t* dispatch_packet = reinterpret_cast<const hsa_kernel_dispatch_packet_t*>(packet);
rocprofiler_callback_data_t data = {dispatch_packet->kernel_object, user_que_idx, obj->agent_info_->dev_index};
hsa_status_t status = on_dispatch_cb_(&data, on_dispatch_cb_data_, &group);
if ((status == HSA_STATUS_SUCCESS) && (group != NULL)) {
Context* context = reinterpret_cast<Context*>(group->context);
const pkt_vector_t& start_vector = context->StartPackets(group->index);
const pkt_vector_t& stop_vector = context->StopPackets(group->index);
pkt_vector_t packets = start_vector;
packets.insert(packets.end(), *packet);
packets.insert(packets.end(), stop_vector.begin(), stop_vector.end());
if (writer != NULL) {
writer(&packets[0], packets.size());
} else {
proxy->Submit(&packets[0], packets.size());
}
to_submit = false;
}
}
if (to_submit) {
if (writer != NULL) {
writer(packet, 1);
} else {
proxy->Submit(packet, 1);
}
}
packet += 1;
}
}
static void SetDispatchCB(rocprofiler_callback_t on_dispatch_cb, void* data) {
std::lock_guard<mutex_t> lck(mutex_);
on_dispatch_cb_ = on_dispatch_cb;
on_dispatch_cb_data_ = data;
}
static void UnsetDispatchCB() {
std::lock_guard<mutex_t> lck(mutex_);
on_dispatch_cb_ = NULL;
on_dispatch_cb_data_ = NULL;
}
private:
InterceptQueue(const hsa_agent_t& agent, ProxyQueue* proxy) : proxy_(proxy) {
agent_info_ = util::HsaRsrcFactory::Instance().GetAgentInfo(agent);
}
~InterceptQueue() { ProxyQueue::Destroy(proxy_); }
static packet_word_t GetHeaderType(const packet_t* packet) {
const packet_word_t* header = reinterpret_cast<const packet_word_t*>(packet);
return (*header >> HSA_PACKET_HEADER_TYPE) & header_type_mask;
}
static mutex_t mutex_;
static const packet_word_t header_type_mask = (1ul << HSA_PACKET_HEADER_WIDTH_TYPE) - 1;
static rocprofiler_callback_t on_dispatch_cb_;
static void* on_dispatch_cb_data_;
static const char* tool_lib_;
static void* tool_handle_;
static obj_map_t* obj_map_;
ProxyQueue* const proxy_;
const util::AgentInfo* agent_info_;
};
} // namespace rocprofiler
#endif // _SRC_CORE_INTERCEPT_QUEUE_H
+169
파일 보기
@@ -0,0 +1,169 @@
#ifndef SRC_CORE_METRICS_H_
#define SRC_CORE_METRICS_H_
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fstream>
#include <iostream>
#include <map>
#include <vector>
#include "core/types.h"
#include "util/exception.h"
#include "util/hsa_rsrc_factory.h"
#include "xml/expr.h"
#include "xml/xml.h"
namespace rocprofiler {
struct counter_t {
std::string name;
event_t event;
};
typedef std::vector<const counter_t*> counters_vec_t;
class Metric {
public:
Metric(const std::string& name) : name_(name) {}
std::string GetName() const { return name_; }
virtual void GetCounters(counters_vec_t &vec) const = 0;
counters_vec_t GetCounters() const {
counters_vec_t counters;
GetCounters(counters);
return counters;
}
virtual const xml::Expr* GetExpr() const = 0;
private:
std::string name_;
};
class BaseMetric : public Metric {
public:
BaseMetric(const std::string& name, const counter_t& counter) : Metric(name), counter_(counter) {}
void GetCounters(counters_vec_t &vec) const { vec.push_back(&counter_); }
const xml::Expr* GetExpr() const { return NULL; }
private:
const counter_t counter_;
};
class ExprMetric : public Metric {
public:
ExprMetric(const std::string& name, const counters_vec_t& counters, const xml::Expr* expr) : Metric(name), counters_(counters), expr_(expr) {}
void GetCounters(counters_vec_t& vec) const { vec.insert(vec.end(), counters_.begin(), counters_.end()); }
const xml::Expr* GetExpr() const { return expr_; }
private:
const counters_vec_t counters_;
const xml::Expr* expr_;
};
class MetricsDict {
public:
typedef std::map<std::string, const Metric*> cache_t;
typedef cache_t::const_iterator const_iterator_t;
class ExprCache : public xml::expr_cache_t {
public:
ExprCache(const cache_t* cache) : cache_(cache) {}
bool Lookup(const std::string& name, std::string& result) const {
bool ret = false;
auto it = cache_->find(name);
if (it != cache_->end()) {
ret = true;
const rocprofiler::ExprMetric* expr_metric = dynamic_cast<const rocprofiler::ExprMetric*>(it->second);
if (expr_metric) result = expr_metric->GetExpr()->GetStr();
}
return ret;
}
private:
const cache_t* const cache_;
};
MetricsDict(const util::AgentInfo* agent_info) : xml_(NULL) {
const char* xml_name = getenv("ROCP_METRICS");
if (xml_name != NULL) {
xml_ = new xml::Xml(xml_name);
std::cout << "ROCProfiler: importing metrics from '" << xml_name << "':" << std::endl;
ImportMetrics(agent_info, agent_info->gfxip);
ImportMetrics(agent_info, "global");
}
}
const Metric* Get(const std::string& name) const {
const Metric* metric = NULL;
auto it = cache_.find(name);
if (it != cache_.end()) metric = it->second;
return metric;
}
private:
void ImportMetrics(const util::AgentInfo* agent_info, const char* scope) {
auto scope_list = xml_->GetNodes("top." + std::string(scope) + ".metric");
if (!scope_list.empty()) {
std::cout << " " << scope_list.size() << " " << scope << " metrics found" << std::endl;
for (auto node : scope_list) {
const std::string name = node->opts["name"];
if (cache_.find(name) != cache_.end()) EXC_RAISING(HSA_STATUS_ERROR, "ImportMetrics: metrics redefined '" << name << "'");
const std::string expr_str = node->opts["expr"];
if (expr_str.empty()) {
const std::string block_name = node->opts["block"];
const uint32_t event_id = atoi(node->opts["event"].c_str());
hsa_ven_amd_aqlprofile_profile_t profile;
profile.agent = agent_info->dev_id;
hsa_ven_amd_aqlprofile_id_query_t query = {block_name.c_str(), 0, 0};
hsa_status_t status = util::HsaRsrcFactory::Instance().AqlProfileApi()->
hsa_ven_amd_aqlprofile_get_info(&profile, HSA_VEN_AMD_AQLPROFILE_INFO_BLOCK_ID, &query);
if (status == HSA_STATUS_SUCCESS) {
const hsa_ven_amd_aqlprofile_block_name_t block_id = (hsa_ven_amd_aqlprofile_block_name_t)query.id;
if (query.instance_count > 1) {
for (unsigned block_index = 0; block_index < query.instance_count; ++block_index) {
std::ostringstream os;
os << name << '[' << block_index << ']';
const std::string full_name = os.str();
const counter_t counter = {full_name, {block_id, block_index, event_id}};
cache_[full_name] = new BaseMetric(full_name, counter);
}
} else {
const counter_t counter = {name, {block_id, 0, event_id}};
cache_[name] = new BaseMetric(name, counter);
}
} else AQL_EXC_RAISING(HSA_STATUS_ERROR, "ImportMetrics: bad block name '" << block_name << "'");
} else {
xml::Expr* expr_obj = new xml::Expr(expr_str, new ExprCache(&cache_));
std::cout << " " << name << " = " << expr_obj->String() << std::endl;
counters_vec_t counters_vec;
for (const std::string var : expr_obj->GetVars()) {
auto it = cache_.find(var);
if (it == cache_.end()) EXC_RAISING(HSA_STATUS_ERROR, "Bad metric '" << name << "', var '" << var << "' is not found");
it->second->GetCounters(counters_vec);
}
cache_[name] = new ExprMetric(name, counters_vec, expr_obj);
}
}
#if 0
for (auto& v : cache_) {
const Metric* metric = v.second;
counters_vec_t counters_vec;
printf("> Metric '%s'\n", metric->GetName().c_str());
metric->GetCounters(counters_vec);
for (auto c : counters_vec) {
printf(" counter %s, b(%u), i (%u), e (%u)\n", c->name.c_str(), c->event.block_name, c->event.block_index, c->event.counter_id);
}
}
#endif
}
}
// Metrics map
xml::Xml* xml_;
cache_t cache_;
};
} // namespace rocprofiler
#endif // SRC_CORE_METRICS_H_
+206
파일 보기
@@ -0,0 +1,206 @@
#ifndef SRC_CORE_PROFILE_H_
#define SRC_CORE_PROFILE_H_
#include "inc/rocprofiler.h"
#include <hsa.h>
#include <vector>
#include "core/types.h"
#include "util/exception.h"
#include "util/hsa_rsrc_factory.h"
namespace rocprofiler {
struct profile_info_t {
const event_t* event;
const parameter_t* parameters;
uint32_t parameter_count;
rocprofiler_info_t* rinfo;
};
typedef std::vector<rocprofiler_info_t*> info_vector_t;
typedef std::vector<packet_t> pkt_vector_t;
struct profile_tuple_t {
const profile_t* profile;
info_vector_t* info_vector;
hsa_signal_t completion_signal;
};
typedef std::vector<profile_tuple_t> profile_vector_t;
template<class Item> class ConfigBase {};
template<> class ConfigBase<event_t> {
public:
ConfigBase(profile_t *profile) : profile_(profile) {}
protected:
void* Array() { return const_cast<event_t*>(profile_->events); }
unsigned Count() const { return profile_->event_count; }
void Set(event_t* events, const unsigned& count) {
profile_->events = events;
profile_->event_count = count;
}
profile_t* profile_;
};
template<> class ConfigBase<parameter_t> {
public:
ConfigBase(profile_t *profile) : profile_(profile) {}
protected:
void* Array() { return const_cast<parameter_t*>(profile_->parameters); }
unsigned Count() const { return profile_->parameter_count; }
void Set(parameter_t* parameters, const unsigned& count) {
profile_->parameters = parameters;
profile_->parameter_count = count;
}
profile_t* profile_;
};
template<class Item>
class Config : protected ConfigBase<Item> {
typedef ConfigBase<Item> Parent;
public:
Config(profile_t *profile) : Parent(profile) {}
void Insert(const Item& item) {
auto count = Parent::Count();
count += 1;
Item* array = reinterpret_cast<Item*>(realloc(const_cast<void*>(Parent::Array()), count * sizeof(Item)));
array[count - 1] = item;
Parent::Set(array, count);
}
};
class Profile {
public:
static const uint32_t LEGACY_SLOT_SIZE_PKT = HSA_VEN_AMD_AQLPROFILE_LEGACY_PM4_PACKET_SIZE / sizeof(packet_t);
Profile(const util::AgentInfo* agent_info) : agent_info_(agent_info) {
profile_ = {};
profile_.agent = agent_info->dev_id;
is_legacy_ = (strncmp(agent_info->name, "gfx8", 4) == 0);
}
virtual ~Profile() {
hsa_memory_free(profile_.command_buffer.ptr);
hsa_memory_free(profile_.output_buffer.ptr);
free(const_cast<event_t*>(profile_.events));
free(const_cast<parameter_t*>(profile_.parameters));
}
virtual void Insert(const profile_info_t& info) {
info_vector_.push_back(info.rinfo);
}
hsa_status_t Finalize(pkt_vector_t& start_vector, pkt_vector_t& stop_vector) {
hsa_status_t status = HSA_STATUS_SUCCESS;
if (!info_vector_.empty()) {
util::HsaRsrcFactory* rsrc = &util::HsaRsrcFactory::Instance();
const pfn_t* api = rsrc->AqlProfileApi();
packet_t start{};
packet_t stop{};
// Check the profile buffer sizes
status = api->hsa_ven_amd_aqlprofile_start(&profile_, NULL);
if (status != HSA_STATUS_SUCCESS) AQL_EXC_RAISING(status, "aqlprofile_start(NULL)");
Allocate(rsrc);
// Generate start/stop profiling packets
status = api->hsa_ven_amd_aqlprofile_start(&profile_, &start);
if (status != HSA_STATUS_SUCCESS) AQL_EXC_RAISING(status, "aqlprofile_start");
status = api->hsa_ven_amd_aqlprofile_stop(&profile_, &stop);
if (status != HSA_STATUS_SUCCESS) AQL_EXC_RAISING(status, "aqlprofile_stop");
// Set completion signals
hsa_signal_t dummy_signal{};
dummy_signal.handle = 0;
start.completion_signal = dummy_signal;
hsa_signal_t post_signal;
status = hsa_signal_create(1, 0, NULL, &post_signal);
if (status != HSA_STATUS_SUCCESS) AQL_EXC_RAISING(status, "hsa_signal_create");
stop.completion_signal = post_signal;
completion_signal_ = post_signal;
if (is_legacy_) {
const uint32_t start_index = start_vector.size();
const uint32_t stop_index = stop_vector.size();
start_vector.insert(start_vector.end(), LEGACY_SLOT_SIZE_PKT, packet_t{});
stop_vector.insert(stop_vector.end(), LEGACY_SLOT_SIZE_PKT, packet_t{});
status = api->hsa_ven_amd_aqlprofile_legacy_get_pm4(&start, reinterpret_cast<void*>(&start_vector[start_index]));
if (status != HSA_STATUS_SUCCESS) AQL_EXC_RAISING(status, "hsa_ven_amd_aqlprofile_legacy_get_pm4");
status = api->hsa_ven_amd_aqlprofile_legacy_get_pm4(&stop, reinterpret_cast<void*>(&stop_vector[stop_index]));
if (status != HSA_STATUS_SUCCESS) AQL_EXC_RAISING(status, "hsa_ven_amd_aqlprofile_legacy_get_pm4");
} else {
start_vector.push_back(start);
stop_vector.push_back(stop);
}
}
return status;
}
void GetProfiles(profile_vector_t& vec) {
if (!info_vector_.empty()) {
vec.push_back(profile_tuple_t{&profile_, &info_vector_, completion_signal_});
}
}
protected:
virtual hsa_status_t Allocate(util::HsaRsrcFactory* rsrc) = 0;
const util::AgentInfo* const agent_info_;
bool is_legacy_;
profile_t profile_;
info_vector_t info_vector_;
hsa_signal_t completion_signal_;
};
class PmcProfile : public Profile {
public:
PmcProfile(const util::AgentInfo* agent_info) : Profile(agent_info) {
profile_.type = HSA_VEN_AMD_AQLPROFILE_EVENT_TYPE_PMC;
}
void Insert(const profile_info_t& info) {
Profile::Insert(info);
Config<event_t>(&profile_).Insert(*(info.event));
}
hsa_status_t Allocate(util::HsaRsrcFactory* rsrc) {
profile_.command_buffer.ptr = rsrc->AllocateSysMemory(agent_info_, profile_.command_buffer.size);
profile_.output_buffer.ptr = rsrc->AllocateSysMemory(agent_info_, profile_.output_buffer.size);
return (profile_.command_buffer.ptr && profile_.output_buffer.ptr) ? HSA_STATUS_SUCCESS : HSA_STATUS_ERROR;
}
};
class SqttProfile : public Profile {
public:
static const uint32_t output_buffer_size = 0x2000000; // 32M
SqttProfile(const util::AgentInfo* agent_info) : Profile(agent_info) {
profile_.type = HSA_VEN_AMD_AQLPROFILE_EVENT_TYPE_SQTT;
}
void Insert(const profile_info_t& info) {
Profile::Insert(info);
for (unsigned j = 0; j < info.parameter_count; ++j) {
Config<parameter_t>(&profile_).Insert(info.parameters[j]);
}
info.rinfo->data.result_bytes.size = output_buffer_size;
if (info.rinfo->data.result_bytes.copy) {
const uint32_t output_buffer_size64 = output_buffer_size / sizeof(uint64_t);
info.rinfo->data.result_bytes.ptr = calloc(output_buffer_size64, sizeof(uint64_t));
memset(info.rinfo->data.result_bytes.ptr, 0, output_buffer_size);
}
}
hsa_status_t Allocate(util::HsaRsrcFactory* rsrc) {
profile_.output_buffer.size = output_buffer_size;
profile_.command_buffer.ptr = rsrc->AllocateSysMemory(agent_info_, profile_.command_buffer.size);
profile_.output_buffer.ptr = rsrc->AllocateLocalMemory(agent_info_, profile_.output_buffer.size);
return (profile_.command_buffer.ptr && profile_.output_buffer.ptr) ? HSA_STATUS_SUCCESS : HSA_STATUS_ERROR;
}
};
} // namespace rocprofiler
#endif // SRC_CORE_PROFILE_H_
+48
파일 보기
@@ -0,0 +1,48 @@
#include "core/proxy_queue.h"
#ifdef ROCP_HSA_PROXY
#include "core/hsa_proxy_queue.h"
#endif
#include "core/simple_proxy_queue.h"
namespace rocprofiler {
void ProxyQueue::HsaIntercept(HsaApiTable* table) {
if (rocp_type_) SimpleProxyQueue::HsaIntercept(table);
}
ProxyQueue* ProxyQueue::Create(
hsa_agent_t agent,
uint32_t size,
hsa_queue_type32_t type,
void (*callback)(hsa_status_t status, hsa_queue_t *source, void *data),
void *data,
uint32_t private_segment_size,
uint32_t group_segment_size,
hsa_queue_t **queue,
hsa_status_t* status)
{
hsa_status_t suc = HSA_STATUS_ERROR;
#ifdef ROCP_HSA_PROXY
ProxyQueue* instance = (rocp_type_) ? (ProxyQueue*) new SimpleProxyQueue() : (ProxyQueue*) new HsaProxyQueue();
#else
ProxyQueue* instance = new SimpleProxyQueue();
#endif
if (instance != NULL) {
const auto suc = instance->Init(agent, size, type, callback, data, private_segment_size, group_segment_size, queue);
if (suc != HSA_STATUS_SUCCESS) {
delete instance;
instance = NULL;
}
}
*status = suc;
return instance;
}
hsa_status_t ProxyQueue::Destroy(const ProxyQueue* obj) {
auto suc = obj->Cleanup();
delete obj;
return suc;
}
bool ProxyQueue::rocp_type_ = false;
} // namespace rocprofiler
+70
파일 보기
@@ -0,0 +1,70 @@
#ifndef _SRC_CORE_PROXY_QUEUE_H
#define _SRC_CORE_PROXY_QUEUE_H
#include <hsa.h>
#include <hsa_api_trace.h>
#include <atomic>
#include <map>
#include <mutex>
#include "core/queue.h"
#include "core/types.h"
struct HsaApiTable;
namespace rocprofiler {
typedef void (*hsa_amd_queue_intercept_packet_writer)(const void* packets, uint64_t count);
typedef void (*on_submit_cb_t)(const void* packet, uint64_t count, uint64_t que_idx, void* data, hsa_amd_queue_intercept_packet_writer writer);
class ProxyQueue : public Queue {
public:
static void InitFactory() {
#ifdef ROCP_HSA_PROXY
const char* type = getenv("ROCP_PROXY_QUEUE");
if (type != NULL) {
if (strncmp(type, "rocp", 4) == 0) rocp_type_ = true;
}
#else
rocp_type_ = true;
#endif
}
static void HsaIntercept(HsaApiTable* table);
static ProxyQueue* Create(
hsa_agent_t agent,
uint32_t size,
hsa_queue_type32_t type,
void (*callback)(hsa_status_t status, hsa_queue_t *source, void *data),
void *data,
uint32_t private_segment_size,
uint32_t group_segment_size,
hsa_queue_t **queue,
hsa_status_t* status);
static hsa_status_t Destroy(const ProxyQueue* obj);
virtual hsa_status_t Init(
hsa_agent_t agent,
uint32_t size,
hsa_queue_type32_t type,
void (*callback)(hsa_status_t status, hsa_queue_t *source, void *data),
void *data,
uint32_t private_segment_size,
uint32_t group_segment_size,
hsa_queue_t **queue
) = 0;
virtual hsa_status_t Cleanup() const = 0;
virtual hsa_status_t SetInterceptCB(on_submit_cb_t on_submit_cb, void* data) = 0;
virtual void Submit(const packet_t* packet) = 0;
protected:
virtual ~ProxyQueue() {};
private:
static bool rocp_type_;
};
} // namespace rocprofiler
#endif // _SRC_CORE_PROXY_QUEUE_H
+20
파일 보기
@@ -0,0 +1,20 @@
#ifndef _SRC_CORE_QUEUE_H
#define _SRC_CORE_QUEUE_H
#include "core/types.h"
namespace rocprofiler {
class Queue {
public:
Queue() {}
virtual ~Queue() {}
virtual void Submit(const packet_t* packet) = 0;
virtual void Submit(const packet_t* packet, const size_t& count) {
for (const packet_t* p = packet; p < packet + count; ++p) Submit(p);
}
};
} // namespace rocprofiler
#endif // _SRC_CORE_QUEUE_H
+251
파일 보기
@@ -0,0 +1,251 @@
#include "inc/rocprofiler.h"
#include <hsa.h>
#include <hsa_api_trace.h>
#include <string.h>
#include <vector>
#include "core/context.h"
#include "core/hsa_queue.h"
#include "core/intercept_queue.h"
#include "core/proxy_queue.h"
#include "core/simple_proxy_queue.h"
#include "util/exception.h"
#include "util/hsa_rsrc_factory.h"
#include "util/logger.h"
#define PUBLIC_API __attribute__((visibility("default")))
#define CONSTRUCTOR_API __attribute__((constructor))
#define DESTRUCTOR_API __attribute__((destructor))
#define API_METHOD_PREFIX \
hsa_status_t status = HSA_STATUS_SUCCESS; \
try {
#define API_METHOD_SUFFIX \
} catch (std::exception& e) { \
ERR_LOGGING(__FUNCTION__ << "(), " << e.what()); \
status = rocprofiler::GetExcStatus(e); \
} \
return status;
namespace rocprofiler {
decltype(hsa_queue_create)* hsa_queue_create_fn;
decltype(hsa_queue_destroy)* hsa_queue_destroy_fn;
decltype(hsa_signal_store_relaxed)* hsa_signal_store_relaxed_fn;
decltype(hsa_queue_load_write_index_relaxed)* hsa_queue_load_write_index_relaxed_fn;
decltype(hsa_queue_store_write_index_relaxed)* hsa_queue_store_write_index_relaxed_fn;
#ifdef ROCP_HSA_PROXY
decltype(hsa_amd_queue_intercept_create)* hsa_amd_queue_intercept_create_fn;
decltype(hsa_amd_queue_intercept_register)* hsa_amd_queue_intercept_register_fn;
#endif
::HsaApiTable* kHsaApiTable;
void SaveHsaApi(::HsaApiTable* table) {
kHsaApiTable = table;
hsa_queue_create_fn = table->core_->hsa_queue_create_fn;
hsa_queue_destroy_fn = table->core_->hsa_queue_destroy_fn;
hsa_signal_store_relaxed_fn = table->core_->hsa_signal_store_relaxed_fn;
hsa_queue_load_write_index_relaxed_fn = table->core_->hsa_queue_load_write_index_relaxed_fn;
hsa_queue_store_write_index_relaxed_fn = table->core_->hsa_queue_store_write_index_relaxed_fn;
#ifdef ROCP_HSA_PROXY
hsa_amd_queue_intercept_create_fn = table->amd_ext_->hsa_amd_queue_intercept_create_fn;
hsa_amd_queue_intercept_register_fn = table->amd_ext_->hsa_amd_queue_intercept_register_fn;
#endif
}
void RestoreHsaApi() {
::HsaApiTable* table = kHsaApiTable;
table->core_->hsa_queue_create_fn = hsa_queue_create_fn;
table->core_->hsa_queue_destroy_fn = hsa_queue_destroy_fn;
table->core_->hsa_signal_store_relaxed_fn = hsa_signal_store_relaxed_fn;
table->core_->hsa_queue_load_write_index_relaxed_fn = hsa_queue_load_write_index_relaxed_fn;
table->core_->hsa_queue_store_write_index_relaxed_fn = hsa_queue_store_write_index_relaxed_fn;
#ifdef ROCP_HSA_PROXY
table->amd_ext_->hsa_amd_queue_intercept_create_fn = hsa_amd_queue_intercept_create_fn;
table->amd_ext_->hsa_amd_queue_intercept_register_fn = hsa_amd_queue_intercept_register_fn;
#endif
}
CONSTRUCTOR_API void constructor() {
util::Logger::Create();
util::HsaRsrcFactory::Create();
}
DESTRUCTOR_API void destructor() {
util::HsaRsrcFactory::Destroy();
util::Logger::Destroy();
}
hsa_status_t GetExcStatus(const std::exception& e) {
const util::exception* rocprofiler_exc_ptr = dynamic_cast<const util::exception*>(&e);
return (rocprofiler_exc_ptr) ? static_cast<hsa_status_t>(rocprofiler_exc_ptr->status()) : HSA_STATUS_ERROR;
}
util::Logger::mutex_t util::Logger::mutex_;
util::Logger* util::Logger::instance_ = NULL;
}
extern "C" {
// Returns the last error message
PUBLIC_API hsa_status_t rocprofiler_error_string(const char** str) {
API_METHOD_PREFIX
*str = rocprofiler::util::Logger::LastMessage().c_str();
API_METHOD_SUFFIX
}
// Create new profiling context
PUBLIC_API hsa_status_t rocprofiler_open(
unsigned agent_id,
rocprofiler_info_t* info,
uint32_t info_count,
rocprofiler_t** handle,
uint32_t mode,
rocprofiler_properties_t* properties)
{
API_METHOD_PREFIX
rocprofiler::util::HsaRsrcFactory* hsa_rsrc = &rocprofiler::util::HsaRsrcFactory::Instance();
const rocprofiler::util::AgentInfo* agent_info;
if (!hsa_rsrc->GetGpuAgentInfo(agent_id, &agent_info)) {
EXC_RAISING(HSA_STATUS_ERROR, "agent[" << agent_id << "] is not found");
}
rocprofiler::Queue* queue = NULL;
if (mode != 0) {
if (mode & ROCPROFILER_MODE_STANDALONE) {
if (mode & ROCPROFILER_MODE_CREATEQUEUE) {
if (hsa_rsrc->CreateQueue(agent_info, properties->queue_depth, &(properties->queue)) == false) {
EXC_RAISING(HSA_STATUS_ERROR, "CreateQueue() failed");
}
}
queue = new rocprofiler::HsaQueue(agent_info, properties->queue);
} else {
EXC_RAISING(HSA_STATUS_ERROR, "invalid mode (" << mode << ")");
}
}
*handle = (void*) new rocprofiler::Context(agent_info, queue, info, info_count);
API_METHOD_SUFFIX
}
// Delete profiling info
PUBLIC_API hsa_status_t rocprofiler_close(rocprofiler_t* handle)
{
API_METHOD_PREFIX
rocprofiler::Context* context = reinterpret_cast<rocprofiler::Context*>(handle);
if (context) delete context;
API_METHOD_SUFFIX
}
// Get profiling groups
PUBLIC_API hsa_status_t rocprofiler_get_groups(rocprofiler_t* handle, rocprofiler_group_t** group_array, uint32_t* group_count) {
API_METHOD_PREFIX
rocprofiler::Context* context = reinterpret_cast<rocprofiler::Context*>(handle);
const uint32_t count = context->GetGroupCount();
rocprofiler_group_t* groups = (rocprofiler_group_t*) calloc(count, sizeof(rocprofiler_group_t));
for (unsigned i = 0; i < count; ++i) groups[i] = context->GetGroupInfo(i);
*group_array = groups;
*group_count = count;
API_METHOD_SUFFIX
}
// Start profiling
PUBLIC_API hsa_status_t rocprofiler_start(rocprofiler_t* handle, uint32_t group_index) {
API_METHOD_PREFIX
rocprofiler::Context* context = reinterpret_cast<rocprofiler::Context*>(handle);
context->Start(group_index);
API_METHOD_SUFFIX
}
// Stop profiling
PUBLIC_API hsa_status_t rocprofiler_stop(rocprofiler_t* handle, uint32_t group_index) {
API_METHOD_PREFIX
rocprofiler::Context* context = reinterpret_cast<rocprofiler::Context*>(handle);
context->Stop(group_index);
API_METHOD_SUFFIX
}
// Get profiling data
PUBLIC_API hsa_status_t rocprofiler_get_data(rocprofiler_t* handle, uint32_t group_index) {
API_METHOD_PREFIX
rocprofiler::Context* context = reinterpret_cast<rocprofiler::Context*>(handle);
context->GetData(group_index);
API_METHOD_SUFFIX
}
// Start profiling
PUBLIC_API hsa_status_t rocprofiler_group_start(rocprofiler_group_t* group) {
API_METHOD_PREFIX
rocprofiler_start(group->context, group->index);
API_METHOD_SUFFIX
}
// Stop profiling
PUBLIC_API hsa_status_t rocprofiler_group_stop(rocprofiler_group_t* group) {
API_METHOD_PREFIX
rocprofiler_stop(group->context, group->index);
API_METHOD_SUFFIX
}
// Get profiling data
PUBLIC_API hsa_status_t rocprofiler_get_group_data(rocprofiler_group_t* group) {
API_METHOD_PREFIX
rocprofiler::Context* context = reinterpret_cast<rocprofiler::Context*>(group->context);
context->GetData(group->index);
API_METHOD_SUFFIX
}
// Get metrics data
PUBLIC_API hsa_status_t rocprofiler_get_metrics_data(const rocprofiler_t* handle) {
API_METHOD_PREFIX
const rocprofiler::Context* context = reinterpret_cast<const rocprofiler::Context*>(handle);
context->GetMetricsData();
API_METHOD_SUFFIX
}
// Set kernel dispatch observer
PUBLIC_API hsa_status_t rocprofiler_set_dispatch_observer(rocprofiler_callback_t callback, void* data) {
API_METHOD_PREFIX
rocprofiler::InterceptQueue::SetDispatchCB(callback, data);
API_METHOD_SUFFIX
}
// Set kernel dispatch observer
PUBLIC_API hsa_status_t rocprofiler_remove_dispatch_observer() {
API_METHOD_PREFIX
rocprofiler::InterceptQueue::UnsetDispatchCB();
API_METHOD_SUFFIX
}
// Method for iterating the events output data
PUBLIC_API hsa_status_t rocprofiler_iterate_trace_data(rocprofiler_t* handle, hsa_ven_amd_aqlprofile_data_callback_t callback, void* data) {
API_METHOD_PREFIX
rocprofiler::Context* context = reinterpret_cast<rocprofiler::Context*>(handle);
context->IterateTraceData(callback, data);
API_METHOD_SUFFIX
}
PUBLIC_API bool OnLoad(
HsaApiTable* table,
uint64_t runtime_version,
uint64_t failed_tool_count,
const char* const * failed_tool_names) {
rocprofiler::SaveHsaApi(table);
rocprofiler::ProxyQueue::InitFactory();
rocprofiler::InterceptQueue::SetTool(getenv("ROCP_TOOL_LIB"));
// HSA intercepting
if (getenv("ROCP_HSA_INTERCEPT") != NULL) {
rocprofiler::InterceptQueue::HsaIntercept(table);
rocprofiler::ProxyQueue::HsaIntercept(table);
}
return true;
}
PUBLIC_API void OnUnload() {
rocprofiler::RestoreHsaApi();
}
} // extern "C"
+11
파일 보기
@@ -0,0 +1,11 @@
#include "core/simple_proxy_queue.h"
namespace rocprofiler {
void SimpleProxyQueue::HsaIntercept(HsaApiTable* table) {
table->core_->hsa_signal_store_relaxed_fn = rocprofiler::SimpleProxyQueue::SignalStore;
table->core_->hsa_queue_load_write_index_relaxed_fn = rocprofiler::SimpleProxyQueue::LoadIndex;
table->core_->hsa_queue_store_write_index_relaxed_fn = rocprofiler::SimpleProxyQueue::StoreIndex;
}
std::map<signal_handle_t, SimpleProxyQueue*> SimpleProxyQueue::queue_map_;
} // namespace rocprofiler
+187
파일 보기
@@ -0,0 +1,187 @@
#ifndef _SRC_CORE_SIMPLE_PROXY_QUEUE_H
#define _SRC_CORE_SIMPLE_PROXY_QUEUE_H
#include <hsa.h>
#include <atomic>
#include <map>
#include <mutex>
#include "core/proxy_queue.h"
#include "core/types.h"
#include "util/hsa_rsrc_factory.h"
namespace rocprofiler {
extern decltype(hsa_queue_create)* hsa_queue_create_fn;
extern decltype(hsa_queue_destroy)* hsa_queue_destroy_fn;
extern decltype(hsa_signal_store_relaxed)* hsa_signal_store_relaxed_fn;
extern decltype(hsa_queue_load_write_index_relaxed)* hsa_queue_load_write_index_relaxed_fn;
extern decltype(hsa_queue_store_write_index_relaxed)* hsa_queue_store_write_index_relaxed_fn;
typedef decltype(hsa_signal_t::handle) signal_handle_t;
class SimpleProxyQueue : public ProxyQueue {
public:
static void HsaIntercept(HsaApiTable* table);
static void SignalStore(
hsa_signal_t signal,
hsa_signal_value_t que_idx)
{
auto it = queue_map_.find(signal.handle);
if (it != queue_map_.end()) {
SimpleProxyQueue* instance = it->second;
const uint64_t begin = instance->submit_index_;
const uint64_t end = que_idx + 1;
instance->submit_index_ = end;
for (uint64_t j = begin; j < end; ++j) {
// Submited packet
const uint32_t idx = j & instance->queue_mask_;
packet_t* packet = reinterpret_cast<packet_t*>(instance->queue_->base_address) + idx;
if (instance->on_submit_cb_ != NULL) instance->on_submit_cb_(packet, 1, j, instance->on_submit_cb_data_, NULL);
else instance->Submit(packet);
}
} else {
hsa_signal_store_relaxed_fn(signal, que_idx);
}
}
static uint64_t LoadIndex(
const hsa_queue_t *queue)
{
uint64_t index = 0;
auto it = queue_map_.find(queue->doorbell_signal.handle);
if (it != queue_map_.end()) {
SimpleProxyQueue* instance = it->second;
instance->mutex_.lock();
index = instance->queue_index_;
} else {
index = hsa_queue_load_write_index_relaxed_fn(queue);
}
return index;
}
static void StoreIndex(
const hsa_queue_t *queue,
uint64_t value)
{
auto it = queue_map_.find(queue->doorbell_signal.handle);
if (it != queue_map_.end()) {
SimpleProxyQueue* instance = it->second;
instance->queue_index_ = value;
instance->mutex_.unlock();
} else {
hsa_queue_store_write_index_relaxed_fn(queue, value);
}
}
hsa_status_t SetInterceptCB(on_submit_cb_t on_submit_cb, void* data) {
on_submit_cb_ = on_submit_cb;
on_submit_cb_data_ = data;
return HSA_STATUS_SUCCESS;
}
void Submit(const packet_t* packet) {
// Compute the write index of queue and copy Aql packet into it
const uint64_t que_idx = hsa_queue_load_write_index_relaxed_fn(queue_);
// Increment the write index and ring the doorbell to submit the packet.
hsa_queue_store_write_index_relaxed_fn(queue_, que_idx + 1);
const uint32_t mask = queue_->size - 1;
const uint32_t idx = que_idx & mask;
// Copy packet to the queue
const packet_word_t* src = reinterpret_cast<const packet_word_t*>(packet);
packet_word_t* dst = reinterpret_cast<packet_word_t*>(base_address_ + idx);
for (unsigned i = 1; i < sizeof(packet_t) / sizeof(packet_word_t); ++i) {
dst[i] = src[i];
}
// To maintain global order to ensure the prior copy of the packet contents is made visible
// before the header is updated.
// With in-order CP it will wait until the first packet in the blob will be valid
std::atomic<packet_word_t>* header_atomic_ptr =
reinterpret_cast<std::atomic<packet_word_t>*>(&dst[0]);
header_atomic_ptr->store(src[0], std::memory_order_release);
// Doorbell signaling
hsa_signal_store_relaxed_fn(doorbell_signal_, que_idx);
}
SimpleProxyQueue() :
agent_info_(NULL),
queue_(NULL),
base_address_(NULL),
doorbell_signal_({}),
queue_index_(0),
queue_mask_(0),
submit_index_(0),
on_submit_cb_(0),
on_submit_cb_data_(0)
{}
~SimpleProxyQueue() {}
private:
hsa_status_t Init(
hsa_agent_t agent,
uint32_t size,
hsa_queue_type32_t type,
void (*callback)(hsa_status_t status, hsa_queue_t *source, void *data),
void *data,
uint32_t private_segment_size,
uint32_t group_segment_size,
hsa_queue_t **queue)
{
auto status = Init(agent, size);
*queue = queue_;
return status;
}
hsa_status_t Init(hsa_agent_t agent, uint32_t size) {
hsa_status_t status = HSA_STATUS_ERROR;
agent_info_ = util::HsaRsrcFactory::Instance().GetAgentInfo(agent);
if (agent_info_ != NULL) {
if (agent_info_->dev_type == HSA_DEVICE_TYPE_GPU) {
status = hsa_queue_create_fn(agent, size, HSA_QUEUE_TYPE_MULTI, NULL, NULL, UINT32_MAX, UINT32_MAX, &queue_);
if (status == HSA_STATUS_SUCCESS) {
base_address_ = reinterpret_cast<packet_t*>(queue_->base_address);
doorbell_signal_ = queue_->doorbell_signal;
data_array_ = calloc(size + 1, sizeof(packet_t));
uintptr_t addr = (uintptr_t)data_array_;
queue_->base_address = (void*) ((addr + align_mask_) & ~align_mask_);
status = hsa_signal_create(1, 0, NULL, &(queue_->doorbell_signal));
queue_mask_ = size - 1;
queue_map_[queue_->doorbell_signal.handle] = this;
}
}
}
return status;
}
hsa_status_t Cleanup() const {
hsa_status_t status = HSA_STATUS_SUCCESS;
queue_->base_address = base_address_;
queue_->doorbell_signal = doorbell_signal_;
status = hsa_queue_destroy_fn(queue_);
free(data_array_);
return status;
}
static std::map<signal_handle_t, SimpleProxyQueue*> queue_map_;
const util::AgentInfo* agent_info_;
hsa_queue_t* queue_;
static const uintptr_t align_mask_ = sizeof(packet_t) - 1;
packet_t* base_address_;
hsa_signal_t doorbell_signal_;
uint64_t queue_index_;
uint64_t queue_mask_;
uint64_t submit_index_;
std::mutex mutex_;
on_submit_cb_t on_submit_cb_;
void* on_submit_cb_data_;
void* data_array_;
};
} // namespace rocprofiler
#endif // _SRC_CORE_SIMPLE_PROXY_QUEUE_H
+15
파일 보기
@@ -0,0 +1,15 @@
#ifndef SRC_CORE_TYPES_H_
#define SRC_CORE_TYPES_H_
#include <hsa_ven_amd_aqlprofile.h>
namespace rocprofiler {
typedef hsa_ven_amd_aqlprofile_1_00_pfn_t pfn_t;
typedef hsa_ven_amd_aqlprofile_event_t event_t;
typedef hsa_ven_amd_aqlprofile_parameter_t parameter_t;
typedef hsa_ven_amd_aqlprofile_profile_t profile_t;
typedef hsa_ext_amd_aql_pm4_packet_t packet_t;
typedef uint32_t packet_word_t;
} // namespace rocprofiler
#endif // SRC_CORE_TYPES_H_
+39
파일 보기
@@ -0,0 +1,39 @@
#ifndef SRC_UTIL_EXCEPTION_H_
#define SRC_UTIL_EXCEPTION_H_
#include <exception>
#include <string>
#include <sstream>
#include <hsa_ven_amd_aqlprofile.h>
#define EXC_RAISING(error, stream) { \
std::ostringstream oss; oss << __FUNCTION__ << "(), " << stream; \
throw rocprofiler::util::exception(error, oss.str()); \
}
#define AQL_EXC_RAISING(error, stream) { \
const char* error_string = NULL; \
const rocprofiler::pfn_t* api = util::HsaRsrcFactory::Instance().AqlProfileApi(); \
api->hsa_ven_amd_aqlprofile_error_string(&error_string); \
EXC_RAISING(error, stream << ", " << error_string); \
}
namespace rocprofiler {
namespace util {
class exception : public std::exception {
public:
explicit exception(const uint32_t &status, const std::string& msg) : status_(status), str_(msg) {}
const char* what() const throw() { return str_.c_str(); }
uint32_t status() const throw() { return status_; }
protected:
const uint32_t status_;
const std::string str_;
};
} // namespace util
} // namespace rocprofiler
#endif // SRC_UTIL_EXCEPTION_H_
+392
파일 보기
@@ -0,0 +1,392 @@
/**********************************************************************
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:
<95> Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
<95> 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 "util/hsa_rsrc_factory.h"
#include <hsa.h>
#include <hsa_ext_finalize.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
namespace rocprofiler {
namespace util {
// Callback function to get available in the system agents
hsa_status_t HsaRsrcFactory::GetHsaAgentsCallback(hsa_agent_t agent, void* data) {
hsa_status_t status = HSA_STATUS_ERROR;
HsaRsrcFactory* hsa_rsrc = reinterpret_cast<HsaRsrcFactory*>(data);
const AgentInfo* agent_info = hsa_rsrc->AddAgentInfo(agent);
if (agent_info != NULL) status = HSA_STATUS_SUCCESS;
return status;
}
// Callback function to find and bind kernarg region of an agent
hsa_status_t HsaRsrcFactory::FindMemRegionsCallback(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;
}
// Constructor of the class
HsaRsrcFactory::HsaRsrcFactory() {
// Initialize the Hsa Runtime
hsa_status_t status = hsa_init();
CHECK_STATUS("Error in hsa_init", status);
// Discover the set of Gpu devices available on the platform
status = hsa_iterate_agents(GetHsaAgentsCallback, this);
CHECK_STATUS("Error Calling hsa_iterate_agents", status);
// Get AqlProfile API table
status = hsa_system_get_extension_table(HSA_EXTENSION_AMD_AQLPROFILE, 1, 0, &aqlprofile_api_);
CHECK_STATUS("aqlprofile API table query failed", status);
}
// Destructor of the class
HsaRsrcFactory::~HsaRsrcFactory() {
hsa_status_t status = hsa_shut_down();
CHECK_STATUS("Error in hsa_shut_down", status);
}
// Add system agent info
const AgentInfo* HsaRsrcFactory::AddAgentInfo(const hsa_agent_t agent) {
// Determine if device is a Gpu agent
hsa_status_t status;
AgentInfo* agent_info = NULL;
hsa_device_type_t type;
status = hsa_agent_get_info(agent, HSA_AGENT_INFO_DEVICE, &type);
CHECK_STATUS("Error Calling hsa_agent_get_info", status);
if (type == HSA_DEVICE_TYPE_CPU) {
agent_info = new AgentInfo{};
agent_info->dev_id = agent;
agent_info->dev_type = HSA_DEVICE_TYPE_CPU;
agent_info->dev_index = cpu_list_.size();
cpu_list_.push_back(agent_info);
}
if (type == HSA_DEVICE_TYPE_GPU) {
agent_info = new 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);
strncpy(agent_info->gfxip, agent_info->name, 4);
agent_info->gfxip[4] = '\0';
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, FindMemRegionsCallback, agent_info);
// Set GPU index
agent_info->dev_index = gpu_list_.size();
gpu_list_.push_back(agent_info);
}
if (agent_info) agent_map_[agent.handle] = agent_info;
return agent_info;
}
// Return systen agent info
const AgentInfo* HsaRsrcFactory::GetAgentInfo(const hsa_agent_t agent) {
const AgentInfo* agent_info = NULL;
auto it = agent_map_.find(agent.handle);
if (it != agent_map_.end()) {
agent_info = it->second;
}
return agent_info;
}
// 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, const 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, const 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(const 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(const AgentInfo* agent_info, size_t size) {
hsa_status_t status;
uint8_t* buffer = NULL;
size = (size + MEM_PAGE_MASK) & ~MEM_PAGE_MASK;
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(const AgentInfo* agent_info, size_t size) {
hsa_status_t status;
size = (size + MEM_PAGE_MASK) & ~MEM_PAGE_MASK;
uint8_t* buffer = NULL;
status = hsa_memory_allocate(agent_info->kernarg_region, size, (void**)&buffer);
return (status == HSA_STATUS_SUCCESS) ? buffer : NULL;
}
// Transfer data method
bool HsaRsrcFactory::TransferData(void* dest_buff, void* 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);
}
// 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(const 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::clog << "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::cerr << "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::cerr << "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::cerr << "Failed to deserialize code object" << std::endl;
return false;
}
// Create executable.
hsa_executable_t hsaExecutable;
status =
hsa_executable_create(HSA_PROFILE_FULL, HSA_EXECUTABLE_STATE_UNFROZEN, "", &hsaExecutable);
CHECK_STATUS("Error in creating executable object", status);
// Load code object.
status = hsa_executable_load_code_object(hsaExecutable, agent_info->dev_id, code_object, "");
CHECK_STATUS("Error in loading executable object", status);
// Freeze executable.
status = hsa_executable_freeze(hsaExecutable, "");
CHECK_STATUS("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_STATUS("Error in looking up kernel symbol", status);
// Update output parameter
*code_desc = kernelSymbol;
return true;
}
// Print the various fields of Hsa Gpu Agents
bool HsaRsrcFactory::PrintGpuAgents(const std::string& header) {
std::clog << header << " :" << std::endl;
const AgentInfo* agent_info;
int size = uint32_t(gpu_list_.size());
for (int idx = 0; idx < size; idx++) {
agent_info = gpu_list_[idx];
std::clog << "> agent[" << idx << "] :" << std::endl;
std::clog << ">> Name : " << agent_info->name << std::endl;
std::clog << ">> Max Wave Size : " << agent_info->max_wave_size << std::endl;
std::clog << ">> Max Queue Size : " << agent_info->max_queue_size << std::endl;
std::clog << ">> Kernarg Region Id : " << agent_info->coarse_region.handle << std::endl;
}
return true;
}
HsaRsrcFactory* HsaRsrcFactory::instance_ = NULL;
HsaRsrcFactory::mutex_t HsaRsrcFactory::mutex_;
} // namespace util
} // namespace rocprofiler
+262
파일 보기
@@ -0,0 +1,262 @@
/**********************************************************************
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:
<95> Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
<95> 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 SRC_UTIL_HSA_RSRC_FACTORY_H_
#define SRC_UTIL_HSA_RSRC_FACTORY_H_
#include <hsa.h>
#include <hsa_ext_finalize.h>
#include <hsa_ven_amd_aqlprofile.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <mutex>
#include <map>
#include <string>
#include <vector>
#define HSA_ARGUMENT_ALIGN_BYTES 16
#define HSA_QUEUE_ALIGN_BYTES 64
#define HSA_PACKET_ALIGN_BYTES 64
#define CHECK_STATUS(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); \
}
namespace rocprofiler {
namespace util {
static const unsigned MEM_PAGE_BYTES = 0x1000;
static const unsigned MEM_PAGE_MASK = MEM_PAGE_BYTES - 1;
typedef decltype(hsa_agent_t::handle) hsa_agent_handle_t;
// Encapsulates information about a Hsa Agent such as its
// handle, name, max queue size, max wavefront size, etc.
struct AgentInfo {
// Handle of Agent
hsa_agent_t dev_id;
// Agent type - Cpu = 0, Gpu = 1 or Dsp = 2
uint32_t dev_type;
// Agent system index
uint32_t dev_index;
// GFXIP name
char gfxip[64];
// 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;
};
class HsaRsrcFactory {
public:
typedef std::recursive_mutex mutex_t;
static HsaRsrcFactory* Create() { return NULL; }
static HsaRsrcFactory* CreateInstance() {
std::lock_guard<mutex_t> lck(mutex_);
if (instance_ == NULL) {
instance_ = new HsaRsrcFactory();
}
return instance_;
}
static HsaRsrcFactory& Instance() {
CreateInstance();
hsa_status_t status = (instance_ != NULL) ? HSA_STATUS_SUCCESS : HSA_STATUS_ERROR;
CHECK_STATUS("HsaRsrcFactory::Instance() is not found", status);
return *instance_;
}
static void Destroy() {
std::lock_guard<mutex_t> lck(mutex_);
if (instance_) delete instance_;
instance_ = NULL;
}
// Return system agent info
const AgentInfo* GetAgentInfo(const hsa_agent_t agent);
// 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, const 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, const 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(const 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(const AgentInfo* agent_info, size_t size);
// 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(const AgentInfo* agent_info, size_t size);
// Transfer data method
bool TransferData(void* dest_buff, void* src_buff, uint32_t length, bool host_to_dev);
// 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(const AgentInfo* agent_info, const char* brig_path, char* kernel_name,
hsa_executable_symbol_t* code_desc);
// Print the various fields of Hsa Gpu Agents
bool PrintGpuAgents(const std::string& header);
// Return AqlProfile API table
const hsa_ven_amd_aqlprofile_1_00_pfn_t* AqlProfileApi() const { return &aqlprofile_api_; }
private:
// System agents iterating callback
static hsa_status_t GetHsaAgentsCallback(hsa_agent_t agent, void* data);
// Callback function to find and bind kernarg region of an agent
static hsa_status_t FindMemRegionsCallback(hsa_region_t region, void* data);
// 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();
// Add an instance of AgentInfo representing a Hsa Gpu agent
const AgentInfo* AddAgentInfo(const hsa_agent_t agent);
static HsaRsrcFactory* instance_;
static mutex_t mutex_;
// Used to maintain a list of Hsa Gpu Agent Info
std::vector<const AgentInfo*> gpu_list_;
// Used to maintain a list of Hsa Cpu Agent Info
std::vector<const AgentInfo*> cpu_list_;
// System agents map
std::map<hsa_agent_handle_t, const AgentInfo*> agent_map_;
// AqlProfile API table
hsa_ven_amd_aqlprofile_1_00_pfn_t aqlprofile_api_;
};
} // namespace util
} // namespace rocprofiler
#endif // SRC_UTIL_HSA_RSRC_FACTORY_H_
+163
파일 보기
@@ -0,0 +1,163 @@
#ifndef SRC_UTIL_LOGGER_H_
#define SRC_UTIL_LOGGER_H_
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/file.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <exception>
#include <mutex>
#include <map>
namespace rocprofiler {
namespace util {
class Logger {
public:
typedef std::recursive_mutex mutex_t;
template <typename T> Logger& operator<<(const T& m) {
std::ostringstream oss;
oss << m;
if (!streaming_)
Log(oss.str());
else
Put(oss.str());
streaming_ = true;
return *this;
}
typedef void (*manip_t)();
Logger& operator<<(manip_t f) {
f();
return *this;
}
static void begm() { Instance().ResetStreaming(true); }
static void endl() { Instance().ResetStreaming(false); }
static const std::string& LastMessage() {
Logger& logger = Instance();
std::lock_guard<mutex_t> lck(mutex_);
return logger.message_[GetTid()];
}
static Logger* Create() {
std::lock_guard<mutex_t> lck(mutex_);
if (instance_ == NULL) instance_ = new Logger();
return instance_;
}
static void Destroy() {
std::lock_guard<mutex_t> lck(mutex_);
if (instance_ != NULL) delete instance_;
instance_ = NULL;
}
static Logger& Instance() {
Create();
return *instance_;
}
private:
static uint32_t GetPid() { return syscall(__NR_getpid); }
static uint32_t GetTid() { return syscall(__NR_gettid); }
Logger() : file_(NULL), dirty_(false), streaming_(false), messaging_(false) {
const char* path = getenv("ROCPROFILER_LOG");
if (path != NULL) {
file_ = fopen("/tmp/rocprofiler_log.txt", "a");
}
ResetStreaming(false);
}
~Logger() {
if (file_ != NULL) {
if (dirty_) Put("\n");
fclose(file_);
}
}
void ResetStreaming(const bool messaging) {
std::lock_guard<mutex_t> lck(mutex_);
if (messaging) {
message_[GetTid()] = "";
}
messaging_ = messaging;
streaming_ = messaging;
}
void Put(const std::string& m) {
std::lock_guard<mutex_t> lck(mutex_);
if (messaging_) {
message_[GetTid()] += m;
}
if (file_ != NULL) {
dirty_ = true;
flock(fileno(file_), LOCK_EX);
fprintf(file_, "%s", m.c_str());
fflush(file_);
flock(fileno(file_), LOCK_UN);
}
}
void Log(const std::string& m) {
const time_t rawtime = time(NULL);
tm tm_info;
localtime_r(&rawtime, &tm_info);
char tm_str[26];
strftime(tm_str, 26, "%Y-%m-%d %H:%M:%S", &tm_info);
std::ostringstream oss;
oss << "<" << tm_str << std::dec << " pid" << GetPid() << " tid" << GetTid() << "> " << m;
Put(oss.str());
}
FILE* file_;
bool dirty_;
bool streaming_;
bool messaging_;
static mutex_t mutex_;
static Logger* instance_;
std::map<uint32_t, std::string> message_;
};
} // namespace util
} // namespace rocprofiler
#define ERR_LOGGING(stream) { \
rocprofiler::util::Logger::Instance() \
<< "error: " \
<< rocprofiler::util::Logger::begm \
<< stream \
<< rocprofiler::util::Logger::endl; \
}
#define INFO_LOGGING(stream) { \
rocprofiler::util::Logger::Instance() \
<< "info: " \
<< rocprofiler::util::Logger::begm \
<< stream \
<< rocprofiler::util::Logger::endl; \
}
#ifdef DEBUG
# define DBG_LOGGING(stream) { \
rocprofiler::util::Logger::Instance() << rocprofiler::util::Logger::begm \
<< "debug: \"" << stream << "\"" << \
<< " in " << __FUNCTION__ \
<< " at " << __FILE__ << " line " << __LINE__ \
<< rocprofiler::util::Logger::endl; \
}
#endif
#endif // SRC_UTIL_LOGGER_H_
+279
파일 보기
@@ -0,0 +1,279 @@
#ifndef _SRC_XML_EXPR_H
#define _SRC_XML_EXPR_H
#include <exception>
#include <map>
#include <string>
#include <iostream>
#include <sstream>
#include <string.h>
namespace xml {
class exception_t : public std::exception {
public:
explicit exception_t(const std::string& msg) : str_(msg) {}
const char* what() const throw() { return str_.c_str(); }
protected:
const std::string str_;
};
typedef uint64_t args_t;
typedef std::map<std::string, args_t> args_map_t;
class Expr;
template <class T>
class any_cache_t {
public:
virtual ~any_cache_t() {}
virtual bool Lookup(const std::string& name, T& result) const = 0;
};
typedef any_cache_t<std::string> expr_cache_t;
typedef any_cache_t<args_t> args_cache_t;
class bin_expr_t {
public:
static const bin_expr_t* CreateExpr(const bin_expr_t* arg1, const bin_expr_t* arg2, const char op);
static const bin_expr_t* CreateArg(Expr *obj, const std::string str);
bin_expr_t() : arg1_(NULL), arg2_(NULL) {}
bin_expr_t(const bin_expr_t* arg1, const bin_expr_t* arg2) : arg1_(arg1), arg2_(arg2) {}
virtual args_t Eval(const args_cache_t& args) const = 0;
virtual std::string Symbol() const = 0;
std::string String() const {
std::string str;
if (arg1_) { str = "(" + arg1_->String() + " " + Symbol() + " " + arg2_->String() + ")"; }
else str = Symbol();
return str;
}
protected:
const bin_expr_t* arg1_;
const bin_expr_t* arg2_;
};
class Expr {
public:
explicit Expr(const std::string& expr, const expr_cache_t* cache) :
expr_(expr),
pos_(0),
sub_count_(0),
cache_(cache)
{
sub_vec_ = new std::vector<const Expr*>;
var_vec_ = new std::vector<std::string>;
tree_ = ParseExpr();
}
explicit Expr(const std::string& expr, const Expr* obj) :
expr_(expr),
pos_(0),
sub_count_(0),
cache_(obj->cache_),
sub_vec_(obj->sub_vec_),
var_vec_(obj->var_vec_)
{
sub_vec_->push_back(this);
tree_ = ParseExpr();
if (!SubCheck()) throw exception_t("expr '" + expr_ + "', bad parenthesis count");
}
~Expr() {
delete cache_;
for (auto it : *sub_vec_) delete it;
delete sub_vec_;
delete var_vec_;
}
std::string GetStr() const { return expr_; }
const expr_cache_t* GetCache() const { return cache_; }
const bin_expr_t* GetTree() const { return tree_; }
args_t Eval(const args_cache_t& args) const { return tree_->Eval(args); }
std::string Lookup(const std::string& str) const {
std::string result;
if (cache_ && !(cache_->Lookup(str, result))) throw exception_t("expr '" + expr_ + "', lookup '" + str + "' failed");
return result;
}
void AddVar(const std::string& str) {
bool found = false;
for (std::string s : *var_vec_) if (s == str) found = true;
if (!found) var_vec_->push_back(str);
}
const std::vector<std::string>& GetVars() const { return *var_vec_; }
std::string String() const { return tree_->String(); }
private:
const bin_expr_t* ParseExpr() {
const bin_expr_t* expr = ParseArg();
while (!IsEnd()) {
const char op = Symb();
const bin_expr_t* second_arg = NULL;
if (IsSymb(')')) {
Next();
SubClose();
break;
} if (IsSymb('*') || IsSymb('/')) {
Next();
second_arg = ParseArg();
expr = bin_expr_t::CreateExpr(expr, second_arg, op);
} else if (IsSymb('+') || IsSymb('-')) {
Next();
second_arg = ParseExpr();
expr = bin_expr_t::CreateExpr(expr, second_arg, op);
break;
} else {
throw exception_t("expr '" + expr_ + "', bad operator '" + op + "'");
}
}
return expr;
}
const bin_expr_t* ParseArg() {
const bin_expr_t* arg = NULL;
if (IsSymb('(')) {
Next();
SubOpen();
arg = ParseExpr();
} else {
const unsigned pos = FindOp();
const std::string str = CutTill(pos);
arg = bin_expr_t::CreateArg(this, str);
if (arg == NULL) throw exception_t("expr '" + expr_ + "', bad argument '" + str + "'");
}
return arg;
}
char Symb() const { return Symb(pos_); }
char Symb(const unsigned ind) const { return expr_[ind]; }
bool IsEnd() const { return (pos_ >= expr_.length()); }
bool IsSymb(const char c) const { return IsSymb(pos_, c); }
bool IsSymb(const unsigned ind, const char c) const { return (expr_[ind] == c); }
void Next() { ++pos_; }
void SubOpen() { ++sub_count_; }
void SubClose() { --sub_count_; }
bool SubCheck() const { return (sub_count_ == 0); }
unsigned FindOp() const {
unsigned i = pos_;
while (i < expr_.length()) {
switch (Symb(i)) {
case '*':
case '/':
case '+':
case '-':
case '(':
case ')':
goto end;
}
++i;
}
end:
return i;
}
std::string CutTill(const unsigned pos) {
const std::string str = (pos > pos_) ? expr_.substr(pos_, pos - pos_) : "";
pos_ = pos;
return str;
}
const std::string expr_;
unsigned pos_;
unsigned sub_count_;
const bin_expr_t* tree_;
const expr_cache_t* const cache_;
std::vector<const Expr*>* sub_vec_;
std::vector<std::string>* var_vec_;
};
class add_expr_t : public bin_expr_t {
public:
add_expr_t(const bin_expr_t* arg1, const bin_expr_t* arg2) : bin_expr_t(arg1, arg2) {}
args_t Eval(const args_cache_t& args) const { return (arg1_->Eval(args) + arg2_->Eval(args)); }
std::string Symbol() const { return "+"; }
};
class sub_expr_t : public bin_expr_t {
public:
sub_expr_t(const bin_expr_t* arg1, const bin_expr_t* arg2) : bin_expr_t(arg1, arg2) {}
args_t Eval(const args_cache_t& args) const { return (arg1_->Eval(args) - arg2_->Eval(args)); }
std::string Symbol() const { return "-"; }
};
class mul_expr_t : public bin_expr_t {
public:
mul_expr_t(const bin_expr_t* arg1, const bin_expr_t* arg2) : bin_expr_t(arg1, arg2) {}
args_t Eval(const args_cache_t& args) const { return (arg1_->Eval(args) * arg2_->Eval(args)); }
std::string Symbol() const { return "*"; }
};
class div_expr_t : public bin_expr_t {
public:
div_expr_t(const bin_expr_t* arg1, const bin_expr_t* arg2) : bin_expr_t(arg1, arg2) {}
args_t Eval(const args_cache_t& args) const { return (arg1_->Eval(args) / arg2_->Eval(args)); }
std::string Symbol() const { return "/"; }
};
class const_expr_t : public bin_expr_t {
public:
const_expr_t(const args_t value) : value_(value) {}
args_t Eval(const args_cache_t&) const { return value_; }
std::string Symbol() const { std::ostringstream os; os << value_; return os.str(); }
private:
const args_t value_;
};
class var_expr_t : public bin_expr_t {
public:
var_expr_t(const std::string name) : name_(name) {}
args_t Eval(const args_cache_t& args) const {
args_t result = 0;
if (!args.Lookup(name_, result)) throw exception_t("expr arg lookup '" + name_ + "' failed");
return result;
}
std::string Symbol() const { return name_; }
private:
const std::string name_;
};
inline const bin_expr_t* bin_expr_t::CreateExpr(const bin_expr_t* arg1, const bin_expr_t* arg2, const char op) {
const bin_expr_t* expr = NULL;
switch (op) {
case '+':
expr = new add_expr_t(arg1, arg2);
break;
case '-':
expr = new sub_expr_t(arg1, arg2);
break;
case '*':
expr = new mul_expr_t(arg1, arg2);
break;
case '/':
expr = new div_expr_t(arg1, arg2);
break;
}
return expr;
}
inline const bin_expr_t* bin_expr_t::CreateArg(Expr* obj, const std::string str) {
const bin_expr_t* arg = NULL;
const unsigned i = strspn(str.c_str(), "1234567890");
if (i == str.length()) {
const unsigned value = atoi(str.c_str());
arg = new const_expr_t(value);
} else {
const std::string sub_expr = obj->Lookup(str);
if (sub_expr.empty()) {
arg = new var_expr_t(str);
obj->AddVar(str);
} else {
const Expr* expr = new Expr(sub_expr, obj);
arg = expr->GetTree();
}
}
return arg;
}
} // namespace xml
#endif // _SRC_XML_EXPR_H
+221
파일 보기
@@ -0,0 +1,221 @@
#ifndef SRC_XML_XML_H_
#define SRC_XML_XML_H_
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fstream>
#include <iostream>
#include <map>
#include <vector>
namespace xml {
class Xml {
public:
typedef std::vector<char> token_t;
struct level_t {
std::string tag;
std::vector<level_t*> nodes;
std::map<std::string, std::string> opts;
};
typedef std::vector<level_t*> nodes_vec_t;
enum {
DECL_STATE,
BODY_STATE
};
Xml(const char* file_name) :
file_name_(file_name),
file_line_(0),
data_size_(0),
index_(0),
state_(BODY_STATE),
level_(NULL),
comment_(false)
{
AddLevel("top");
fd_ = open(file_name, O_RDONLY);
if (fd_ == -1) {
std::cout << "XML file not found: " << file_name << std::endl;
return;
}
token_t remainder;
while (1) {
token_t token = (remainder.size()) ? remainder : NextToken();
remainder.clear();
// End of file
if (token.size() == 0) break;
// token_t token1 = token;
// token1.push_back('\0');
// std::cout << "> " << &token1[0] << std::endl;
switch(state_) {
case BODY_STATE:
if (token[0] == '<') {
bool node_begin = true;
unsigned ind = 1;
if (token[1] == '/') {
node_begin = false;
++ind;
}
unsigned i = ind;
while (i < token.size()) { if (token[i] == '>') break; ++i; }
for (unsigned j = i + 1; j < token.size(); ++j) remainder.push_back(token[j]);
if (i == token.size()) {
if (node_begin) state_ = DECL_STATE;
else BadFormat(token);
token.push_back('\0');
} else token[i] = '\0';
const char* tag = strdup(&token[ind]);
if (node_begin) {
AddLevel(tag);
} else {
if (strncmp(CurrentLevel().c_str(), tag, strlen(tag))) {
token.back() = '>';
BadFormat(token);
}
UpLevel();
}
} else BadFormat(token);
break;
case DECL_STATE:
if (token[0] == '>') {
state_ = BODY_STATE;
for (unsigned j = 1; j < token.size(); ++j) remainder.push_back(token[j]);
continue;
} else {
token.push_back('\0');
unsigned j = 0;
for (j = 0; j < token.size(); ++j) if (token[j] == '=') break;
if (j == token.size()) BadFormat(token);
token[j] = '\0';
const char* key = &token[0];
const char* value = &token[j + 1];
AddOption(key, value);
}
break;
default:
std::cout << "Wrong state: " << state_ << std::endl;
exit(1);
}
}
}
std::vector<level_t*> GetNodes(std::string global_tag) {
return map_[global_tag];
}
void Print() const {
for(auto& elem : map_) {
for (auto node : elem.second) {
if (node->opts.size()) {
std::cout << elem.first << ":" << std::endl;
for (auto& opt : node->opts) {
std::cout << " " << opt.first << " = " << opt.second << std::endl;
}
}
}
}
}
private:
bool LineEndCheck() {
bool found = false;
if (buffer_[index_] == '\n') {
buffer_[index_] = ' ';
++file_line_;
found = true;
comment_ = false;
} else if (comment_ || (buffer_[index_] == '#')) {
found = true;
comment_ = true;
}
return found;
}
token_t NextToken() {
token_t token;
while (1) {
if (data_size_ == 0) {
data_size_ = read(fd_, buffer_, buf_size_);
if (data_size_ <= 0) break;
}
if (token.empty()) while ((index_ < data_size_) && ((buffer_[index_] == ' ') || LineEndCheck())) {
++index_;
}
while ((index_ < data_size_) && (buffer_[index_] != ' ') && !LineEndCheck()) {
token.push_back(buffer_[index_++]);
}
if (index_ == data_size_) {
index_ = 0;
data_size_ = 0;
} else break;
}
return token;
}
void BadFormat(token_t token) {
token.push_back('\0');
std::cout << "Error: " << file_name_ << ", line " << file_line_ << ", bad XML token '" << &token[0] << "'" << std::endl;
exit(1);
}
void AddLevel(const std::string& tag) {
level_t* level = new level_t;
level->tag = tag;
if (level_) {
level_->nodes.push_back(level);
stack_.push_back(level_);
}
level_ = level;
std::string global_tag;
for (level_t* level : stack_) { global_tag += level->tag + "."; }
global_tag += tag;
map_[global_tag].push_back(level_);
}
void UpLevel() {
level_ = stack_.back();
stack_.pop_back();
}
std::string CurrentLevel() const {
return level_->tag;
}
void AddOption(const std::string& key, const std::string& value) {
level_->opts[key] = value;
}
const char* file_name_;
unsigned file_line_;
int fd_;
static const unsigned buf_size_ = 256;
char buffer_[buf_size_];
unsigned data_size_;
unsigned index_;
unsigned state_;
level_t* level_;
std::vector<level_t*> stack_;
std::map<std::string, nodes_vec_t> map_;
bool comment_;
};
} // namespace xml
#endif // SRC_XML_XML_H_