* -------------------------------------------------------------------------
* This file is part of the MindStudio project.
* Copyright (c) 2025 Huawei Technologies Co.,Ltd.
*
* MindStudio is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* 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 FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*/
#include <unordered_map>
#include <algorithm>
#include "SourceFileParser.h"
#include "NumberUtil.h"
#include "DetailsService.h"
namespace Dic {
namespace Module {
namespace Source {
bool DetailsService::QueryDetailsLoadInfo(
const SourceDetailsLoadInfoRequest &request, DetailsLoadInfoResponse &response) {
DetailsLoadInfoResBody compareBody;
bool result = SourceFileParser::Instance().GetDetailsLoadInfo(compareBody, false);
if (!result) {
return false;
}
response.body = compareBody;
if (!request.params.isCompared) {
return true;
}
DetailsLoadInfoResBody baselineBody;
bool baselineRes = SourceFileParser::Instance().GetDetailsLoadInfo(baselineBody, true);
if (!baselineRes) {
return true;
}
response.body.chartData = MergeSubBlockData(compareBody.chartData, baselineBody.chartData);
response.body.tableData = MergeSubBlockData(compareBody.tableData, baselineBody.tableData);
return true;
}
SubBlockData DetailsService::MergeSubBlockData(const SubBlockData &compare, const SubBlockData &baseline) {
std::unordered_map<std::string, CompareData<SubBlockUnitData>> subBlockDataMap;
for (const auto &item : compare.detailDataList) {
std::string key = GetSubBlockDataKey(item.compare);
if (key.empty()) {
continue;
}
subBlockDataMap[key] = item;
subBlockDataMap[key].baseline.BaseInfoClone(subBlockDataMap[key].compare);
subBlockDataMap[key].diff.BaseInfoClone(subBlockDataMap[key].compare);
}
for (const auto &item : baseline.detailDataList) {
std::string key = GetSubBlockDataKey(item.compare);
if (key.empty()) {
continue;
}
SubBlockUnitData baselineData = item.compare;
if (subBlockDataMap.find(key) != subBlockDataMap.end()) {
SubBlockUnitData compareData = subBlockDataMap[key].compare;
subBlockDataMap[key].diff.blockId = baselineData.blockId;
subBlockDataMap[key].diff.name = baselineData.name;
subBlockDataMap[key].diff.blockType = baselineData.blockType;
subBlockDataMap[key].diff.unit = baselineData.unit;
subBlockDataMap[key].diff.value =
NumberUtil::StringDoubleMinusWithoutTrailingZero(compareData.value, baselineData.value);
subBlockDataMap[key].diff.originValue =
NumberUtil::StringDoubleMinusWithoutTrailingZero(compareData.originValue, baselineData.originValue);
subBlockDataMap[key].baseline = baselineData;
}
}
SubBlockData res;
for (const auto &item : subBlockDataMap) {
res.detailDataList.push_back(item.second);
}
return res;
}
std::string DetailsService::GetSubBlockDataKey(const SubBlockUnitData &data) {
return data.blockId + underline + data.blockType + data.name;
}
bool DetailsService::QueryMemoryGraph(const DetailsMemoryGraphRequest &request, DetailsMemoryGraphResponse &response) {
DetailsMemoryGraphResBody compareBody;
bool result = SourceFileParser::Instance().GetDetailsMemoryGraph(request.params.blockId, false, compareBody);
if (!result) {
return false;
}
response.body = compareBody;
if (!request.params.isCompared) {
return true;
}
DetailsMemoryGraphResBody baselineBody;
bool baselineRes = SourceFileParser::Instance().GetDetailsMemoryGraph(request.params.blockId, true, baselineBody);
if (!baselineRes) {
return true;
}
response.body.coreMemory = MergeMemoryGraph(compareBody.coreMemory, baselineBody.coreMemory);
return true;
}
std::vector<MemoryGraph> DetailsService::MergeMemoryGraph(
const std::vector<MemoryGraph> &compare, const std::vector<MemoryGraph> &baseline) {
std::unordered_map<std::string, MemoryGraph> subMemoryGraphMap;
for (const auto &item : compare) {
subMemoryGraphMap[item.blockId] = item;
}
for (const auto &item : baseline) {
MemoryGraph &compareGraph = subMemoryGraphMap[item.blockId];
if (compareGraph.blockId.empty()) {
compareGraph.blockId = item.blockId;
compareGraph.blockType = item.blockType;
compareGraph.chipType = item.chipType;
}
compareGraph.advice = std::vector<std::string>();
compareGraph.l2Cache = MergeL2Cache(compareGraph.l2Cache.compare, item.l2Cache.compare);
compareGraph.vector = MergeUtilizationRate(compareGraph.vector.compare, item.vector.compare);
compareGraph.vector1 = MergeUtilizationRate(compareGraph.vector1.compare, item.vector1.compare);
compareGraph.cube = MergeUtilizationRate(compareGraph.cube.compare, item.cube.compare);
compareGraph.memoryUnit = MergeMemoryUnit(compareGraph.memoryUnit, item.memoryUnit);
}
std::vector<MemoryGraph> res;
res.reserve(subMemoryGraphMap.size());
for (const auto &item : subMemoryGraphMap) {
res.push_back(item.second);
}
return res;
}
std::vector<CompareData<MemoryUnit>> DetailsService::MergeMemoryUnit(
const std::vector<CompareData<MemoryUnit>> &compare, const std::vector<CompareData<MemoryUnit>> &baseline) {
std::unordered_map<std::string, CompareData<MemoryUnit>> memoryUnitMap;
for (const auto &item : compare) {
memoryUnitMap[item.compare.memoryPath] = item;
}
for (const auto &item : baseline) {
MemoryUnit baselineMemoryUnit = item.compare;
if (memoryUnitMap.find(baselineMemoryUnit.memoryPath) != memoryUnitMap.end()) {
MemoryUnit compareMemoryUnit = memoryUnitMap[baselineMemoryUnit.memoryPath].compare;
MemoryUnit diff;
diff.memoryPath = baselineMemoryUnit.memoryPath;
diff.request =
NumberUtil::StringUnsignedLongLongMinus(compareMemoryUnit.request, baselineMemoryUnit.request);
diff.requestSuffix = compareMemoryUnit.requestSuffix;
diff.bandwidth = NumberUtil::StringDoubleMinusWithoutTrailingZero(
compareMemoryUnit.bandwidth, baselineMemoryUnit.bandwidth);
diff.bandwidthSuffix = compareMemoryUnit.bandwidthSuffix;
diff.peakRatio = NumberUtil::StringDoubleMinusWithoutTrailingZero(
compareMemoryUnit.peakRatio, baselineMemoryUnit.peakRatio);
diff.display = compareMemoryUnit.display;
memoryUnitMap[baselineMemoryUnit.memoryPath].diff = diff;
}
memoryUnitMap[baselineMemoryUnit.memoryPath].baseline = baselineMemoryUnit;
}
std::vector<CompareData<MemoryUnit>> res;
res.reserve(memoryUnitMap.size());
for (const auto &item : memoryUnitMap) {
res.push_back(item.second);
}
return res;
}
CompareData<Protocol::L2Cache> DetailsService::MergeL2Cache(const L2Cache &compare, const L2Cache &baseline) {
CompareData<L2Cache> res;
res.compare = compare;
res.baseline = baseline;
res.diff.totalRequest =
NumberUtil::StringDoubleMinusWithoutTrailingZero(res.compare.totalRequest, res.baseline.totalRequest);
res.diff.miss = NumberUtil::StringDoubleMinusWithoutTrailingZero(res.compare.miss, res.baseline.miss);
res.diff.hit = NumberUtil::StringDoubleMinusWithoutTrailingZero(res.compare.hit, res.baseline.hit);
res.diff.hitRatio = NumberUtil::StringDoubleMinusWithoutTrailingZero(res.compare.hitRatio, res.baseline.hitRatio);
return res;
}
CompareData<UtilizationRate> DetailsService::MergeUtilizationRate(
const UtilizationRate &compare, const UtilizationRate &baseline) {
CompareData<UtilizationRate> res;
res.compare = compare;
res.baseline = baseline;
res.diff.ratio = NumberUtil::StringDoubleMinusWithoutTrailingZero(res.compare.ratio, res.baseline.ratio);
res.diff.totalCycles =
NumberUtil::StringDoubleMinusWithoutTrailingZero(res.compare.totalCycles, res.baseline.totalCycles);
res.diff.cycle = NumberUtil::StringDoubleMinusWithoutTrailingZero(res.compare.cycle, res.baseline.cycle);
return res;
}
bool DetailsService::QueryMemoryTable(const DetailsMemoryTableRequest &request, DetailsMemoryTableResponse &response) {
DetailsMemoryTableResBody compareBody;
bool result = SourceFileParser::Instance().GetDetailsMemoryTable(request.params.blockId, false, compareBody);
if (!result) {
return false;
}
response.body = compareBody;
if (!request.params.isCompared) {
return true;
}
DetailsMemoryTableResBody baselineBody;
bool baselineRes = SourceFileParser::Instance().GetDetailsMemoryTable(request.params.blockId, true, baselineBody);
if (!baselineRes) {
return true;
}
response.body.memoryTable = MergeMemoryTables(compareBody.memoryTable, baselineBody.memoryTable);
return true;
}
std::vector<MemoryTable> DetailsService::MergeMemoryTables(
const std::vector<MemoryTable> &compare, const std::vector<MemoryTable> &baseline) {
std::unordered_map<std::string, MemoryTable> memoryTableMap;
for (const auto &item : compare) {
memoryTableMap[item.blockId] = item;
memoryTableMap[item.blockId].FillBaseInfoFromCompare();
}
for (const auto &item : baseline) {
MemoryTable &table = memoryTableMap[item.blockId];
if (table.blockId.empty()) {
table.blockId = item.blockId;
table.advice = std::vector<std::string>();
table.tableOpType = item.tableOpType;
}
table.tableDetail = MergeCompareTableList(table.tableDetail, item.tableDetail);
}
std::vector<MemoryTable> res;
res.reserve(memoryTableMap.size());
for (const auto &item : memoryTableMap) {
res.push_back(item.second);
}
return res;
}
std::vector<TableDetail<CompareData<TableRow>>> DetailsService::MergeCompareTableList(
const std::vector<TableDetail<CompareData<TableRow>>> &compare,
const std::vector<TableDetail<CompareData<TableRow>>> &baseline) {
std::unordered_map<std::string, TableDetail<CompareData<TableRow>>> memoryTableDetailMap;
for (const auto &item : compare) {
memoryTableDetailMap[item.tableName] = item;
}
for (const auto &item : baseline) {
if (memoryTableDetailMap.count(item.tableName) == 0) {
continue;
}
TableDetail<CompareData<TableRow>> &tableDetail = memoryTableDetailMap[item.tableName];
tableDetail.row = MergeCompareRows(memoryTableDetailMap[item.tableName].row, item.row);
std::vector<std::string> newSize = {
std::to_string(tableDetail.headerName.size()), std::to_string(tableDetail.row.size())};
tableDetail.size = newSize;
}
std::vector<TableDetail<CompareData<TableRow>>> res;
res.reserve(memoryTableDetailMap.size());
for (const auto &item : memoryTableDetailMap) {
res.push_back(item.second);
}
return res;
}
std::vector<CompareData<TableRow>> DetailsService::MergeCompareRows(
const std::vector<CompareData<TableRow>> &compare, const std::vector<CompareData<TableRow>> &baseline) {
std::vector<CompareData<TableRow>> res;
std::unordered_map<std::string, CompareData<TableRow>> tableRowMap;
for (const auto &item : compare) {
tableRowMap[item.compare.name] = item;
}
for (const auto &item : baseline) {
std::string rowName = item.compare.name;
if (tableRowMap.find(rowName) != tableRowMap.end()) {
unsigned long long colNum = std::min(tableRowMap[rowName].compare.value.size(), item.compare.value.size());
for (unsigned long long i = 0; i < colNum; ++i) {
tableRowMap[rowName].diff.value[i] = NumberUtil::StringDoubleMinusWithoutTrailingZero(
tableRowMap[rowName].compare.value[i], item.compare.value[i]);
}
tableRowMap[rowName].baseline = item.compare;
}
}
res.reserve(tableRowMap.size());
for (const auto &item : tableRowMap) {
res.push_back(item.second);
}
return res;
}
bool DetailsService::QueryCoreLoadAnalysisGraph(
const DetailsInterCoreLoadGraphRequest &request, DetailsInterCoreLoadGraphResponse &response) {
DetailsInterCoreLoadGraphBody compareBody;
bool result = SourceFileParser::Instance().GetDetailsInterCoreLoadAnalysisGraph(compareBody, false);
if (!result) {
return false;
}
response.body = compareBody;
if (!request.params.isCompared) {
return true;
}
DetailsInterCoreLoadGraphBody baselineBody;
bool baselineRes = SourceFileParser::Instance().GetDetailsInterCoreLoadAnalysisGraph(baselineBody, true);
if (!baselineRes) {
return true;
}
response.body.opDetails = MergeCoreLoadOpDetail(compareBody.opDetails, baselineBody.opDetails);
return true;
}
std::vector<DetailsInterCoreLoadOpDetail> DetailsService::MergeCoreLoadOpDetail(
const std::vector<DetailsInterCoreLoadOpDetail> &compare,
const std::vector<DetailsInterCoreLoadOpDetail> &baseline) {
std::unordered_map<uint8_t, DetailsInterCoreLoadOpDetail> opDetailMap;
for (const auto &item : compare) {
opDetailMap[item.coreId] = item;
}
for (const auto &item : baseline) {
if (opDetailMap.find(item.coreId) == opDetailMap.end()) {
continue;
}
opDetailMap[item.coreId].subCoreDetails =
MergeCoreDetail(opDetailMap[item.coreId].subCoreDetails, item.subCoreDetails);
}
std::vector<DetailsInterCoreLoadOpDetail> result;
result.reserve(opDetailMap.size());
for (const auto &item : opDetailMap) {
result.push_back(item.second);
}
return result;
}
std::vector<DetailsInterCoreLoadSubCoreDetail> DetailsService::MergeCoreDetail(
const std::vector<DetailsInterCoreLoadSubCoreDetail> &compare,
const std::vector<DetailsInterCoreLoadSubCoreDetail> &baseline) {
std::unordered_map<std::string, DetailsInterCoreLoadSubCoreDetail> coreDetailMap;
for (const auto &item : compare) {
coreDetailMap[item.subCoreName] = item;
}
for (const auto &item : baseline) {
if (coreDetailMap.find(item.subCoreName) == coreDetailMap.end()) {
continue;
}
DetailsInterCoreLoadSubCoreDetail &detail = coreDetailMap[item.subCoreName];
detail.cycles.value.baseline = item.cycles.value.compare;
detail.cycles.value.diff = NumberSafe::Sub(item.cycles.value.compare, detail.cycles.value.baseline);
detail.throughput.value.baseline = item.throughput.value.compare;
detail.throughput.value.diff = NumberSafe::Sub(item.throughput.value.compare, detail.throughput.value.baseline);
detail.cacheHitRate.value.baseline = item.cacheHitRate.value.compare;
detail.cacheHitRate.value.diff =
NumberSafe::Sub(item.cacheHitRate.value.compare, detail.cacheHitRate.value.baseline);
}
std::vector<DetailsInterCoreLoadSubCoreDetail> result;
result.reserve(coreDetailMap.size());
for (const auto &item : coreDetailMap) {
result.push_back(item.second);
}
return result;
}
}
}
}