* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
* \file Reporter.cpp
* \brief
*/
#include <iomanip>
#include <sstream>
#include <vector>
#include "cost_model/simulation/base/Reporter.h"
using namespace std;
namespace CostModel {
Reporter::Reporter() = default;
void Reporter::PrintName(string const& name, uint32_t len)
{
if (len == 0) {
cout << left << setw(NAME_WIDTH - 1) << setfill('.') << name << ':';
return;
}
string output = std::string(INDENT_WIDTH * len, ' ') + "|--" + name;
cout << left << setw(NAME_WIDTH - 1) << setfill('.') << output << ':';
}
void Reporter::ReportTitle(string const& title)
{
int fillWidth = TOTAL_WIDTH - title.length();
int leftWidth = fillWidth / 2;
int rightWidth = fillWidth - leftWidth;
cout << string(leftWidth, '=') << title << string(rightWidth, '=') << endl;
}
void Reporter::ReportMap(const std::string& name, std::map<uint64_t, uint64_t>& vals)
{
cout << left << setw(NAME_WIDTH - 1) << setfill('.') << name << ':' << endl;
vector<pair<string, string>> columns;
vector<size_t> widths;
size_t count = 0;
for (const auto& val : vals) {
string index = to_string(val.first);
string value = to_string(val.second);
columns.emplace_back(index, value);
if (count >= widths.size()) {
widths.push_back(max(index.length(), value.length()));
} else {
widths[count] = max(widths[count], max(index.length(), value.length()));
}
count++;
}
int displayWidth = 6;
for (size_t i = 0; i < columns.size(); i++) {
if (i % displayWidth == 0) {
if (i > 0) {
cout << endl;
}
cout << " |";
}
string index = columns[i].first;
size_t spaces = widths[i] - index.length();
size_t leftSpaces = spaces / 2;
size_t rightSpaces = spaces - leftSpaces;
cout << " " << string(leftSpaces, ' ') << index << string(rightSpaces, ' ') << " |";
if ((i + 1) % displayWidth == 0 || i == columns.size() - 1) {
cout << endl << " |";
for (size_t j = i / displayWidth * displayWidth; j <= i; j++) {
cout << " " << setw(int(widths[j])) << right << columns[j].second << " |";
}
cout << endl;
}
}
}
void Reporter::ReportMapAndPct(const std::string& name, std::map<int, uint64_t>& vals, const uint64_t& baseVal)
{
cout << left << setw(NAME_WIDTH - 1) << setfill('.') << name << ':' << endl;
vector<pair<string, string>> columns;
vector<size_t> widths;
size_t count = 0;
for (const auto& val : vals) {
string index = to_string(val.first);
stringstream ss;
ss << fixed << setprecision(floatPrec) << (float(val.second) / float(baseVal) * basePercent) << "%";
string ratio = ss.str();
columns.emplace_back(index, ratio);
if (count >= widths.size()) {
widths.push_back(max(index.length(), ratio.length()));
} else {
widths[count] = max(widths[count], max(index.length(), ratio.length()));
}
count++;
}
int displayWidth = 6;
for (size_t i = 0; i < columns.size(); i++) {
if (i % displayWidth == 0) {
if (i > 0) {
cout << endl;
}
cout << " |";
}
string index = columns[i].first;
size_t spaces = widths[i] - index.length();
size_t leftSpaces = spaces / 2;
size_t rightSpaces = spaces - leftSpaces;
cout << " " << string(leftSpaces, ' ') << index << string(rightSpaces, ' ') << " |";
if ((i + 1) % displayWidth == 0 || i == columns.size() - 1) {
cout << endl << " |";
for (size_t j = i / displayWidth * displayWidth; j <= i; j++) {
cout << " " << setw(int(widths[j])) << right << columns[j].second << " |";
}
cout << endl;
}
}
}
void Reporter::ReportMapsAndPct(
const std::string& name, std::map<int, uint64_t>& vals, std::map<int, uint64_t>& baseVals)
{
cout << left << setw(NAME_WIDTH - 1) << setfill('.') << name << ':' << endl;
vector<pair<string, string>> columns;
vector<size_t> widths;
size_t count = 0;
for (const auto& val : vals) {
string index = to_string(val.first);
stringstream ss;
if (baseVals.find(val.first) != baseVals.end() && baseVals[val.first] != 0) {
ss << fixed << setprecision(floatPrec) << (float(val.second) / float(baseVals[val.first]) * basePercent)
<< "%";
} else {
ss << "nan%";
}
string ratio = ss.str();
columns.emplace_back(index, ratio);
if (count >= widths.size()) {
widths.push_back(max(index.length(), ratio.length()));
} else {
widths[count] = max(widths[count], max(index.length(), ratio.length()));
}
count++;
}
int displayWidth = 6;
for (size_t i = 0; i < columns.size(); i++) {
if (i % displayWidth == 0) {
if (i > 0) {
cout << endl;
}
cout << " |";
}
string index = columns[i].first;
size_t spaces = widths[i] - index.length();
size_t leftSpaces = spaces / 2;
size_t rightSpaces = spaces - leftSpaces;
cout << " " << string(leftSpaces, ' ') << index << string(rightSpaces, ' ') << " |";
if ((i + 1) % displayWidth == 0 || i == columns.size() - 1) {
cout << endl << " |";
for (size_t j = i / displayWidth * displayWidth; j <= i; j++) {
cout << " " << setw(int(widths[j])) << right << columns[j].second << " |";
}
cout << endl;
}
}
}
void Reporter::ReportValWithLvl(const std::string& name, uint64_t val, uint32_t level)
{
PrintName(name, level);
cout << right << setw(VAL_WIDTH) << setfill(' ') << dec << val << endl;
}
void Reporter::ReportValWithLvl(const std::string& name, float val, uint32_t level)
{
PrintName(name, level);
cout << right << setw(VAL_WIDTH) << setfill(' ') << setiosflags(ios::fixed) << setprecision(floatPrec) << val
<< endl;
}
void Reporter::ReportValWithLvl(const std::string& name, double val, uint32_t level)
{
PrintName(name, level);
cout << right << setw(VAL_WIDTH) << setfill(' ') << setiosflags(ios::fixed) << setprecision(floatPrec) << val
<< endl;
}
void Reporter::ReportVal(string const& name, uint64_t val) { ReportValWithLvl(name, val, 0); }
void Reporter::ReportVal(string const& name, float val) { ReportValWithLvl(name, val, 0); }
void Reporter::ReportVal(string const& name, double val) { ReportValWithLvl(name, val, 0); }
void Reporter::ReportAvg(string const& name, uint64_t numerator, uint64_t denominator)
{
ReportAvg(name, static_cast<float>(numerator), static_cast<float>(denominator));
}
void Reporter::ReportAvg(string const& name, float numerator, float denominator)
{
PrintName(name, 0);
cout << right << setw(VAL_WIDTH) << setfill(' ') << setiosflags(ios::fixed) << setprecision(floatPrec);
if (denominator >= 0.0) {
cout << numerator / denominator << endl;
} else {
cout << "nan" << endl;
}
}
void Reporter::ReportPctWithLvl(const std::string& name, float rate, uint32_t level)
{
PrintName(name, level);
cout << right << setw(VAL_WIDTH) << setfill(' ');
cout << fixed << setprecision(floatPrec) << rate * basePercent << '%' << endl;
}
void Reporter::ReportPct(string const& name, uint64_t numerator, uint64_t denominator)
{
ReportPct(name, static_cast<float>(numerator), static_cast<float>(denominator));
}
void Reporter::ReportPct(string const& name, float numerator, float denominator)
{
PrintName(name, 0);
cout << right << setw(VAL_WIDTH) << setfill(' ');
if (denominator >= 0.0) {
cout << fixed << setprecision(floatPrec) << numerator / denominator * basePercent << '%' << endl;
} else {
cout << "nan%" << endl;
}
}
void Reporter::ReportPct(string const& name, float rate) { ReportPctWithLvl(name, rate, 0); }
void Reporter::ReportValAndPctWithLvl(const std::string& name, uint64_t numerator, uint64_t denominator, uint32_t level)
{
PrintName(name, level);
cout << right << setw(VAL_WIDTH) << setfill(' ') << dec << numerator << ' ';
cout << setw(PCT_WIDTH) << setfill(' ');
if (denominator != 0) {
cout << fixed << setprecision(floatPrec) << float(numerator) / float(denominator) * basePercent << '%' << endl;
} else {
cout << "nan%" << endl;
}
}
void Reporter::ReportValAndPct(string const& name, uint64_t numerator, uint64_t denominator)
{
ReportValAndPctWithLvl(name, numerator, denominator, 0);
}
void Reporter::ReportValAndPctWithLvl(const std::string& name, float numerator, uint64_t denominator, uint32_t level)
{
PrintName(name, level);
cout << right << setw(VAL_WIDTH) << setfill(' ') << dec << numerator << ' ';
cout << setw(PCT_WIDTH) << setfill(' ');
if (denominator != 0) {
cout << fixed << setprecision(floatPrec) << numerator / float(denominator) * basePercent << '%' << endl;
} else {
cout << "nan%" << endl;
}
}
void Reporter::ReportValAndPct(const string& name, float numerator, uint64_t denominator)
{
ReportValAndPctWithLvl(name, numerator, denominator, 0);
}
void Reporter::ReportValAndPctFlWithLvl(const std::string& name, double numerator, double denominator, uint32_t level)
{
PrintName(name, level);
cout << right << setw(VAL_WIDTH) << setfill(' ') << dec << numerator << ' ';
cout << setw(PCT_WIDTH) << setfill(' ');
if (denominator >= 0.0) {
cout << fixed << setprecision(floatPrec) << float(numerator) / float(denominator) * basePercent << '%' << endl;
} else {
cout << "nan%" << endl;
}
}
void Reporter::ReportValAndPctFl(string const& name, double numerator, double denominator)
{
ReportValAndPctFlWithLvl(name, numerator, denominator, 0);
}
void Reporter::ReportHexCounter(const std::string& name, uint64_t pc, uint64_t counter)
{
cout << left << name << setw((NAME_WIDTH - 1) - name.length()) << setfill('.') << hex << pc << ':';
cout << right << setw(VAL_WIDTH) << setfill(' ') << dec << counter << endl;
}
void Reporter::ReportStallLoc(string const& name, uint64_t localBpc, uint64_t localTpc, uint64_t peerBpc, uint64_t val)
{
stringstream ss;
string newName;
ss << name << "local_0x" << hex << localBpc << "_0x" << hex << localTpc << "---peer_0x" << hex << peerBpc;
ss >> newName;
cout << left << setw(NAME_WIDTH - 1) << setfill('.') << newName << ':';
cout << right << setw(VAL_WIDTH) << setfill(' ') << setiosflags(ios::fixed) << setprecision(floatPrec) << val
<< endl;
}
std::streambuf* Reporter::ReportSetOutStreamFile(string const& fileName)
{
if (fout.is_open()) {
fout.close();
}
fout.open(fileName, ios::out | ios::trunc);
return cout.rdbuf(fout.rdbuf());
}
std::streambuf* Reporter::ReportSetOutStreamFile(string const& fileName, bool isApp)
{
if (fout.is_open()) {
fout.close();
}
if (isApp) {
fout.open(fileName, ios::out | ios::app);
} else {
fout.open(fileName, ios::out | ios::ate);
}
return cout.rdbuf(fout.rdbuf());
}
void Reporter::ReportResetOutStreamCout(std::streambuf* pOld)
{
if (pOld == nullptr) {
return;
}
cout.rdbuf(pOld);
if (fout.is_open()) {
fout.close();
}
}
}