* -------------------------------------------------------------------------
* 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 "InterCoreLoadGraphParser.h"
#include "JsonUtil.h"
namespace Dic::Module::Source {
using namespace Dic::Protocol;
using namespace Dic::Server;
bool InterCoreLoadGraphParser::GetInterCoreLoadAnalysisInfo(
const std::string &json, Protocol::DetailsInterCoreLoadGraphBody &body) {
std::optional<InterCoreLoadAnalysisDetail> analysisDetailOpt = ParseInterCoreLoadAnalysisInfo(json);
if (!analysisDetailOpt.has_value()) {
return false;
}
InterCoreLoadAnalysisDetail &analysisDetail = analysisDetailOpt.value();
body.advice = analysisDetail.advice;
body.opType = analysisDetail.opType;
body.soc = analysisDetail.soc;
for (const auto &opDetail : analysisDetail.opDetails) {
DetailsInterCoreLoadOpDetail bodyOpDetail;
bodyOpDetail.coreId = opDetail.coreId;
for (const auto &subCoreDetail : opDetail.subCoreDetails) {
DetailsInterCoreLoadSubCoreDetail bodySubCoreDetail;
bodySubCoreDetail.SetCyclesDimension(static_cast<int64_t>(subCoreDetail.cycles),
cyclesSigmodStats[subCoreDetail.subCoreType].average,
cyclesSigmodStats[subCoreDetail.subCoreType].sigma);
bodySubCoreDetail.SetThroughputDimension(static_cast<int64_t>(subCoreDetail.throughput),
throughputSigmodStats[subCoreDetail.subCoreType].average,
throughputSigmodStats[subCoreDetail.subCoreType].sigma);
bodySubCoreDetail.SetCacheHitRateDimension(subCoreDetail.hitRate,
cacheHitRatioSigmodStats[subCoreDetail.subCoreType].average,
cacheHitRatioSigmodStats[subCoreDetail.subCoreType].sigma);
bodySubCoreDetail.SetSimtVfInstruction(subCoreDetail.simtVfInstructions,
simtVfInstructionSigmodStats[subCoreDetail.subCoreType].average,
simtVfInstructionSigmodStats[subCoreDetail.subCoreType].sigma);
bodySubCoreDetail.SetSimtVfInstructionPerCycle(subCoreDetail.simtVfInstructionPerCycle);
bodySubCoreDetail.SetSubCoreName(subCoreDetail.subCoreType, subCoreDetail.subCoreIndex);
bodyOpDetail.AddSubCoreDetail(std::move(bodySubCoreDetail));
}
body.AddOpDetail(std::move(bodyOpDetail));
}
return true;
}
{ // 核间负载分析数据块结构
"soc": str, // 算子运行平台
"op_type": str, // 算子类型:vector, cube, mix
"advice": str, // 分析结果
"op_detail": [
{
"core_id": uint8, // core序号
"core_detail": [
{
"subcore_id": uint8, // 0、1
"subcore_type": str // cube、vector
"cycles": uint64, // 耗时(cycle)
"throughput" : float32, // 核吞吐数据量(GB/s)
" L2cache _hit_rate" : float32 // L2cache命中率 (%)
}
]
}
]
}
*/
std::optional<InterCoreLoadAnalysisDetail> InterCoreLoadGraphParser::ParseInterCoreLoadAnalysisInfo(
const std::string &json) {
if (json.empty()) {
ServerLog::Warn("Inter core load analysis json string is empty.");
return std::nullopt;
}
InterCoreLoadAnalysisDetail analysisDetail;
try {
std::string errorStr;
const std::optional<document_t> &jsonInfo = JsonUtil::TryParse<kParseNumbersAsStringsFlag>(json, errorStr);
if (!errorStr.empty() || !jsonInfo.has_value()) {
ServerLog::Error("Try to parse inter core load analysis json string failed, error is ", errorStr);
return std::nullopt;
}
const document_t &jsonInfoDoc = jsonInfo.value();
analysisDetail.soc = JsonUtil::GetString(jsonInfoDoc, "soc");
analysisDetail.opType = JsonUtil::GetString(jsonInfoDoc, "op_type");
analysisDetail.advice = JsonUtil::GetString(jsonInfoDoc, "advice");
if (!JsonUtil::IsJsonArray(jsonInfoDoc, "op_detail")) {
ServerLog::Warn("Try to parse inter core load analysis json failed cause op detail is not an array.");
return std::nullopt;
}
const json_t &jsonOpDetailArray = jsonInfoDoc["op_detail"];
ParseJsonOpDetailArray(analysisDetail, jsonOpDetailArray);
} catch (const std::exception &e) {
ServerLog::Error("Try to parse inter core load analysis json failed, exception is ", e.what());
return std::nullopt;
}
return {std::move(analysisDetail)};
}
void InterCoreLoadGraphParser::ParseJsonOpDetailArray(
InterCoreLoadAnalysisDetail &analysisDetail, const json_t &jsonOpDetailArray) {
std::string_view errMsg;
for (auto &jsonOpDetail : jsonOpDetailArray.GetArray()) {
InterCoreOpDetail opDetail;
opDetail.coreId = JsonUtil::GetInteger(jsonOpDetail, "core_id");
if (!JsonUtil::IsJsonArray(jsonOpDetail, "core_detail")) {
if (errMsg.empty()) {
errMsg = "Found sub core detail is not array when parse inter core load analysis json.";
}
analysisDetail.AddOpDetail(std::move(opDetail));
continue;
}
const json_t &jsonCoreDetailArray = jsonOpDetail["core_detail"];
for (const json_t &jsonCoreDetail : jsonCoreDetailArray.GetArray()) {
InterCoreSubCoreDetail subCoreDetail;
subCoreDetail.subCoreIndex = JsonUtil::GetInteger(jsonCoreDetail, "subcore_id");
subCoreDetail.subCoreType = JsonUtil::GetString(jsonCoreDetail, "subcore_type");
int64_t tmp = JsonUtil::GetInteger(jsonCoreDetail, "cycles");
subCoreDetail.cycles = tmp < 0 ? 0 : static_cast<uint64_t>(tmp);
tmp = JsonUtil::GetInteger(jsonCoreDetail, "throughput");
subCoreDetail.throughput = tmp < 0 ? 0 : static_cast<uint64_t>(tmp);
subCoreDetail.hitRate = JsonUtil::GetFloat(jsonCoreDetail, "L2cache_hit_rate");
if (jsonCoreDetail.HasMember("simt_vf_instructions") && jsonCoreDetail["simt_vf_instructions"].IsObject()) {
auto &simt = jsonCoreDetail["simt_vf_instructions"];
subCoreDetail.simtVfInstructions = JsonUtil::GetInteger(simt, "instructions");
subCoreDetail.simtVfInstructionPerCycle = JsonUtil::GetFloat(simt, "instruction_per_cycle");
}
opDetail.subCoreDetails.emplace_back(subCoreDetail);
UpdateSigmodStats(subCoreDetail);
}
analysisDetail.AddOpDetail(std::move(opDetail));
}
FinishSigmodStats();
if (!errMsg.empty()) {
ServerLog::Warn(errMsg);
}
TransformAnalysisDetail(analysisDetail);
}
void InterCoreLoadGraphParser::TransformAnalysisDetail(InterCoreLoadAnalysisDetail &analysisDetail) {
if (analysisDetail.opType != "vector") {
return;
}
std::sort(analysisDetail.opDetails.begin(), analysisDetail.opDetails.end(),
[](const InterCoreOpDetail &a, const InterCoreOpDetail &b) { return a.coreId < b.coreId; });
std::vector<InterCoreOpDetail> newOpDetails;
uint8_t index = 0;
while (index < std::numeric_limits<uint8_t>::max() - 2 && index < analysisDetail.opDetails.size()) {
uint8_t coreId = static_cast<uint8_t>(index / 2);
InterCoreOpDetail detail;
detail.coreId = coreId;
Try2MoveSubCoreDetails(analysisDetail.opDetails[index], detail, SUB_CORE_INDEX_0);
if (++index < analysisDetail.opDetails.size()) {
Try2MoveSubCoreDetails(analysisDetail.opDetails[index], detail, SUB_CORE_INDEX_1);
}
newOpDetails.emplace_back(detail);
index++;
}
analysisDetail.opDetails = std::move(newOpDetails);
}
void InterCoreLoadGraphParser::Try2MoveSubCoreDetails(
InterCoreOpDetail &source, InterCoreOpDetail &dest, uint8_t subCoreIndex) {
if (!source.subCoreDetails.empty()) {
auto subCoreDetail = source.subCoreDetails[0];
subCoreDetail.subCoreIndex = subCoreIndex;
dest.subCoreDetails.emplace_back(subCoreDetail);
}
}
void InterCoreLoadGraphParser::UpdateSigmodStats(const InterCoreSubCoreDetail &detail) {
cyclesSigmodStats[detail.subCoreType].data.push_back(static_cast<long double>(detail.cycles));
throughputSigmodStats[detail.subCoreType].data.push_back(static_cast<long double>(detail.throughput));
cacheHitRatioSigmodStats[detail.subCoreType].data.push_back(static_cast<long double>(detail.hitRate));
simtVfInstructionSigmodStats[detail.subCoreType].data.push_back(
static_cast<long double>(detail.simtVfInstructions));
}
void InterCoreLoadGraphParser::FinishSigmodStats() {
std::for_each(cyclesSigmodStats.begin(), cyclesSigmodStats.end(), [](auto &item) { item.second.CalculateSigma(); });
std::for_each(
throughputSigmodStats.begin(), throughputSigmodStats.end(), [](auto &item) { item.second.CalculateSigma(); });
std::for_each(cacheHitRatioSigmodStats.begin(), cacheHitRatioSigmodStats.end(),
[](auto &item) { item.second.CalculateSigma(); });
std::for_each(simtVfInstructionSigmodStats.begin(), simtVfInstructionSigmodStats.end(),
[](auto &item) { item.second.CalculateSigma(); });
}
}