diff --git a/bin/rpl_run.sh b/bin/rpl_run.sh index e6133c664f..134b9b2fc1 100755 --- a/bin/rpl_run.sh +++ b/bin/rpl_run.sh @@ -327,10 +327,9 @@ done if [ -n "$csv_output" ] ; then python $BIN_DIR/tblextr.py $csv_output $OUTPUT_LIST - if [ "$?" = 1 ] ; then - error "CSV generation error, profiling results '$RES_DIR'" + if [ "$?" -eq 0 ] ; then + echo "RPL: '$csv_output' is generated" fi - echo "RPL: '$csv_output' is generated" fi if [ "$DATA_PATH" = "$TMP_DIR" ] ; then diff --git a/bin/tblextr.py b/bin/tblextr.py index b18065e1ae..ebd878e8f0 100755 --- a/bin/tblextr.py +++ b/bin/tblextr.py @@ -83,6 +83,7 @@ def parse_res(infile): # print results table method def print_tbl(outfile): global var_list + if len(var_table) == 0: return 1 out = open(outfile, 'w') @@ -107,6 +108,7 @@ def print_tbl(outfile): out.write("\n") out.close() + return 0 ############################################################# # main @@ -116,6 +118,6 @@ outfile = sys.argv[1] infiles = sys.argv[2:] for f in infiles : parse_res(f) -print_tbl(outfile) -sys.exit(0) +ret = print_tbl(outfile) +sys.exit(ret) ############################################################# diff --git a/src/core/context.h b/src/core/context.h index 8d3a259dad..db3b76e39d 100644 --- a/src/core/context.h +++ b/src/core/context.h @@ -33,6 +33,7 @@ SOFTWARE. #include #include +#include "core/group_set.h" #include "core/metrics.h" #include "core/profile.h" #include "core/queue.h" @@ -48,7 +49,7 @@ class Context; inline unsigned align_size(unsigned size, unsigned alignment) { return ((size + alignment - 1) & ~(alignment - 1)); } - +#if 0 // Block descriptor struct block_des_t { uint32_t id; @@ -68,7 +69,7 @@ struct block_status_t { uint32_t counter_index; uint32_t group_index; }; - +#endif // Metrics arguments template class MetricArgs : public xml::args_cache_t { public: @@ -181,7 +182,12 @@ class Context { { metrics_ = MetricsDict::Create(agent_info); if (metrics_ == NULL) EXC_RAISING(HSA_STATUS_ERROR, "MetricsDict create failed"); - Initialize(info, info_count); + if (Initialize(info, info_count) == false) { + fprintf(stdout, "\nInput metrics out of HW limit. Proposed metrics group set:\n"); fflush(stdout); + MetricsGroupSet(agent_info, info, info_count).Print(stdout); + fprintf(stdout, "\n"); fflush(stdout); + EXC_RAISING(HSA_STATUS_ERROR, "Metrics list exceeds HW limits"); + } Finalize(); if (handler != NULL) { @@ -209,7 +215,7 @@ class Context { } // Initialize rocprofiler context - void Initialize(rocprofiler_feature_t* info_array, const uint32_t info_count) { + bool Initialize(rocprofiler_feature_t* info_array, const uint32_t info_count) { // Register input features to not duplicate by features referencing for (unsigned i = 0; i < info_count; ++i) { rocprofiler_feature_t* info = &info_array[i]; @@ -272,9 +278,12 @@ class Context { block_status.max_counters = block_counters; } if (block_status.counter_index >= block_status.max_counters) { + return false; + block_status.counter_index = 0; block_status.group_index += 1; } + block_status.counter_index += 1; if (block_status.group_index >= set_.size()) { set_.push_back(Group(agent_info_, this, block_status.group_index)); } @@ -287,6 +296,8 @@ class Context { EXC_RAISING(HSA_STATUS_ERROR, "bad rocprofiler feature kind (" << kind << ")"); } } + + return true; } void Finalize() { diff --git a/src/core/group_set.h b/src/core/group_set.h new file mode 100644 index 0000000000..b52e865cee --- /dev/null +++ b/src/core/group_set.h @@ -0,0 +1,246 @@ +/****************************************************************************** +MIT License + +Copyright (c) 2018 ROCm Core Technology + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*******************************************************************************/ + +#ifndef SRC_CORE_GROUP_SET_H_ +#define SRC_CORE_GROUP_SET_H_ + +#include +#include +#include + +#include "core/metrics.h" +#include "util/exception.h" +#include "util/hsa_rsrc_factory.h" + +namespace rocprofiler { + +// 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 set class +class MetricsGroup { + public: + // Info map type + typedef std::map info_map_t; + // Blocks map type + typedef std::map blocks_map_t; + + MetricsGroup(const util::AgentInfo* agent_info) : + agent_info_(agent_info) + { + metrics_ = MetricsDict::Create(agent_info); + if (metrics_ == NULL) EXC_RAISING(HSA_STATUS_ERROR, "MetricsDict create failed"); + } + + void Print(FILE* file) const { + for (const Metric* metric : metrics_vec_) { + fprintf(file, " %s", metric->GetName().c_str()); fflush(stdout); + } + fprintf(file, "\n"); fflush(stdout); + } + + static const Metric* GetMetric(const MetricsDict* metrics, const std::string& name) { + // Metric object + const Metric* metric = metrics->Get(name); + if (metric == NULL) + EXC_RAISING(HSA_STATUS_ERROR, "input metric '" << name << "' is not found"); + return metric; + } + + static const Metric* GetMetric(const MetricsDict* metrics, const rocprofiler_feature_t* info) { + // Metrics name + const char* name = info->name; + if (name == NULL) EXC_RAISING(HSA_STATUS_ERROR, "input feature name is NULL"); + const Metric* metric = GetMetric(metrics, name); +#if 0 + std::cout << " " << name << (metric->GetExpr() ? " = " + metric->GetExpr()->String() : " counter") << std::endl; +#endif + return metric; + } + + // Add metric + bool AddMetric(const rocprofiler_feature_t* info) { + return AddMetric(GetMetric(metrics_, info)); + } + + bool AddMetric(const Metric* metric) { + // Blocks utilization delta + blocks_map_t blocks_delta; + + // Process metrics counters + const counters_vec_t& counters_vec = metric->GetCounters(); + if (counters_vec.empty()) + EXC_RAISING(HSA_STATUS_ERROR, "bad metric '" << metric->GetName() << "' is empty"); + + for (const counter_t* counter : counters_vec) { + const event_t* event = &(counter->event); + + // For metrics expressions checking that there is no the same counter in the input metrics + // and also that the counter wasn't registered already by another input metric expression + if (info_map_.find(counter->name) != info_map_.end()) continue; + + const block_des_t block_des = {event->block_name, event->block_index}; + auto ret = blocks_map_.insert({block_des, {}}); + block_status_t& block_status = ret.first->second; + if (ret.second == true) { + profile_t query = {}; + query.agent = agent_info_->dev_id; + query.type = HSA_VEN_AMD_AQLPROFILE_EVENT_TYPE_PMC; + query.events = event; + + uint32_t block_counters; + hsa_status_t status = util::HsaRsrcFactory::Instance().AqlProfileApi()->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; + } + + ret = blocks_delta.insert({block_des, block_status}); + block_status_t& delta_status = ret.first->second; + delta_status.counter_index += 1; + if (delta_status.counter_index > delta_status.max_counters) return false; + } + + // Register metric + metrics_vec_.push_back(metric); + info_map_[metric->GetName()] = metric; + for (const counter_t* counter : counters_vec) { + if (info_map_.find(counter->name) == info_map_.end()) info_map_[counter->name] = NewCounterInfo(counter->name); + } + for (const auto& entry : blocks_delta) { + blocks_map_[entry.first] = entry.second; + } + + return true; + } + + private: + const Metric* NewCounterInfo(const std::string& name) const { + return GetMetric(metrics_, name); + } + + // Agent info + const util::AgentInfo* const agent_info_; + // Metrics dictionary + const MetricsDict* metrics_; + // Info map + info_map_t info_map_; + // Blocks map + blocks_map_t blocks_map_; + // Metrics vector + std::vector metrics_vec_; +}; + +// Metrics groups class +class MetricsGroupSet { + public: + MetricsGroupSet(const util::AgentInfo* agent_info, const rocprofiler_feature_t* info_array, const uint32_t info_count) : + agent_info_(agent_info) + { + metrics_ = MetricsDict::Create(agent_info); + if (metrics_ == NULL) EXC_RAISING(HSA_STATUS_ERROR, "MetricsDict create failed"); + Initialize(info_array, info_count); + } + + ~MetricsGroupSet() { + for (auto* group : groups_) delete group; + } + + uint32_t GetSize() const { return groups_.size(); } + + void Print(FILE* file) const { + uint32_t idx = 0; + for (const auto* group : groups_) { + ++idx; + fprintf(stdout, " group%u:", idx); fflush(stdout); + group->Print(file); + } + } + + private: + void Initialize(const rocprofiler_feature_t* info_array, const uint32_t info_count) { + std::multimap input_metrics; + for (unsigned i = 0; i < info_count; ++i) { + const rocprofiler_feature_t* info = &info_array[i]; + if (info->kind != ROCPROFILER_FEATURE_KIND_METRIC) continue; + const Metric* metric = MetricsGroup::GetMetric(metrics_, info); + const uint32_t counters_num = metric->GetCounters().size(); + input_metrics.insert({counters_num, metric}); + + if (MetricsGroup(agent_info_).AddMetric(metric) == false) { + AQL_EXC_RAISING(HSA_STATUS_ERROR, "Metric '" << metric->GetName() << "' doesn't fit in one group"); + } + } + uint32_t group_num = 0; + while (input_metrics.size() != 0) { + MetricsGroup* group = NextGroup(); + ++group_num; + auto it = input_metrics.end(); + --it; + bool to_cont = true; + do { + const Metric* metric = it->second; + const bool to_erase = (group->AddMetric(metric) == true); + to_cont = (it != input_metrics.begin()); + + auto curr = it; + if (to_cont) --it; + if (to_erase) input_metrics.erase(curr); + } while (to_cont); + } + } + + MetricsGroup* NextGroup() { + groups_.push_back(new MetricsGroup(agent_info_)); + return groups_.back(); + } + + // Agent info + const util::AgentInfo* const agent_info_; + // Metrics dictionary + const MetricsDict* metrics_; + // Metrics group vector + std::vector groups_; +}; + +} // namespace rocprofiler + +#endif // SRC_CORE_GROUP_SET_H_