* Copyright (c) 2026 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 memory_tracer.cpp
*/
#include "memory_tracer.h"
#include <fstream>
#include "tilefwk/platform.h"
#include "tilefwk/data_type.h"
#include "passes/pass_log/pass_log.h"
#define MODULE_NAME "MemoryTracer"
namespace npu::tile_fwk {
namespace {
constexpr const char* TRACE_VERSION = "2.5";
constexpr const char* FALLBACK_ARCH = "DAV_2201";
}
std::string MemoryTracer::PipeTypeToStr(PipeType p)
{
switch (p) {
case PipeType::PIPE_S: return "PIPE_S";
case PipeType::PIPE_V: return "PIPE_V";
case PipeType::PIPE_V2: return "PIPE_V2";
case PipeType::PIPE_M: return "PIPE_M";
case PipeType::PIPE_MTE1: return "PIPE_MTE1";
case PipeType::PIPE_MTE2: return "PIPE_MTE2";
case PipeType::PIPE_MTE3: return "PIPE_MTE3";
case PipeType::PIPE_FIX: return "PIPE_FIX";
default: return "PIPE_UNKNOWN";
}
}
std::string MemoryTracer::CoreClassToStr(CoreClass c)
{
switch (c) {
case CoreClass::AIC: return "AIC";
case CoreClass::AIV: return "AIV";
default: return "UNKNOWN";
}
}
std::string MemoryTracer::DDRKindToStr(DDRBufferKind k)
{
switch (k) {
case DDRBufferKind::FUNCTION_TEMP: return "FUNCTION_TEMP";
case DDRBufferKind::SPILL_TEMP: return "SPILL_TEMP";
case DDRBufferKind::INCAST: return "INCAST";
case DDRBufferKind::OUTCAST: return "OUTCAST";
default: return "UNKNOWN";
}
}
MemoryTracer::Json MemoryTracer::DDRRefToJson(const DDRRef& ref)
{
Json j;
j["memId"] = ref.memId;
j["kind"] = DDRKindToStr(ref.kind);
j["memType"] = MemoryTypeToString(ref.memType);
j["addrStart"] = ref.addrStart;
j["addrEnd"] = ref.addrEnd;
j["size"] = ref.size;
return j;
}
void MemoryTracer::OnOpLaunch(const OpLaunchEvent& e)
{
if (!inMainLoop_) return;
if (spillCopyoutOpMagics_.count(e.opMagic) != 0) return;
Json event;
event["eventType"] = "OP_LAUNCH";
event["clock"] = e.clock;
event["opMagic"] = e.opMagic;
event["cycleEnd"] = e.cycleEnd;
event["pipeType"] = PipeTypeToStr(e.pipeType);
event["coreType"] = CoreClassToStr(e.coreLocation.coreType);
event["coreIdx"] = e.coreLocation.coreIdx;
event["inputMemIds"] = e.inputMemIds;
event["outputMemIds"] = e.outputMemIds;
Json refs = Json::array();
for (const auto& r : e.ddrRefs) refs.push_back(DDRRefToJson(r));
event["ddrRefs"] = std::move(refs);
timeline_.push_back(std::move(event));
}
void MemoryTracer::OnOpRetire(const OpRetireEvent& e)
{
if (!inMainLoop_) return;
if (spillCopyoutOpMagics_.count(e.opMagic) != 0) return;
Json event;
event["eventType"] = "OP_RETIRE";
event["clock"] = e.clock;
event["opMagic"] = e.opMagic;
event["freedMemIds"] = e.freedMemIds;
timeline_.push_back(std::move(event));
}
void MemoryTracer::OnAllocExec(const AllocExecEvent& e)
{
if (!inMainLoop_) return;
Json event;
event["eventType"] = "ALLOC_EXEC";
event["clock"] = e.clock;
event["memId"] = e.memId;
event["memType"] = MemoryTypeToString(e.memType);
event["coreType"] = CoreClassToStr(e.coreLocation.coreType);
event["coreIdx"] = e.coreLocation.coreIdx;
event["addrStart"] = e.addrStart;
event["addrEnd"] = e.addrEnd;
event["size"] = e.addrEnd - e.addrStart;
Json lts = Json::array();
for (const auto& lt : e.logicalTensors) {
Json l;
l["magic"] = lt.magic;
l["validSize"] = lt.validSize;
lts.push_back(std::move(l));
}
event["logicalTensors"] = std::move(lts);
timeline_.push_back(std::move(event));
}
void MemoryTracer::OnSpill(const SpillEvent& e)
{
if (!inMainLoop_) return;
if (e.spillCopyoutOpMagic != -1) {
spillCopyoutOpMagics_.insert(e.spillCopyoutOpMagic);
}
Json event;
event["eventType"] = "SPILL";
event["clock"] = e.clock;
event["beginClock"] = e.beginClock;
event["endClock"] = e.endClock;
event["memId"] = e.spillMemId;
event["memType"] = MemoryTypeToString(e.memType);
event["coreType"] = CoreClassToStr(e.coreLocation.coreType);
event["coreIdx"] = e.coreLocation.coreIdx;
event["addrStart"] = e.addrStart;
event["addrEnd"] = e.addrEnd;
event["triggerOpMagic"] = e.triggerOpMagic;
event["triggerTensorSize"] = e.triggerTensorSize;
event["spillCopyoutOpMagic"] = e.spillCopyoutOpMagic;
event["reloadAllocOpMagic"] = e.reloadAllocOpMagic;
event["reloadCopyInOpMagic"] = e.reloadCopyInOpMagic;
event["spillTensorMagic"] = e.spillTensorMagic;
event["spillCopyoutSize"] = e.spillCopyoutSize;
if (e.spillDdrMemId != -1) {
event["spillDdrMemId"] = e.spillDdrMemId;
event["ddrKind"] = DDRKindToStr(e.ddrKind);
event["ddrMemType"] = MemoryTypeToString(e.ddrMemType);
event["ddrAddrStart"] = e.ddrAddrStart;
event["ddrAddrEnd"] = e.ddrAddrEnd;
event["ddrSize"] = e.ddrSize;
}
timeline_.push_back(std::move(event));
}
void MemoryTracer::OnBufferRearrange(const BufferRearrangeEvent& e)
{
if (!inMainLoop_) return;
Json event;
event["eventType"] = "BUFFER_REARRANGE";
event["clock"] = e.clock;
event["memType"] = MemoryTypeToString(e.memType);
event["coreType"] = CoreClassToStr(e.coreLocation.coreType);
event["coreIdx"] = e.coreLocation.coreIdx;
event["triggerOpMagic"] = e.triggerOpMagic;
Json changes = Json::array();
for (const auto& c : e.changes) {
Json item;
item["memId"] = c.memId;
item["oldStart"] = c.oldStart;
item["oldEnd"] = c.oldEnd;
item["newStart"] = c.newStart;
item["newEnd"] = c.newEnd;
changes.push_back(std::move(item));
}
event["changes"] = std::move(changes);
timeline_.push_back(std::move(event));
}
void MemoryTracer::OnAllocFail(const AllocFailEvent& e)
{
if (!inMainLoop_) return;
Json event;
event["eventType"] = "ALLOC_FAIL";
event["clock"] = e.clock;
event["triggerOpMagic"] = e.triggerOpMagic;
event["memType"] = MemoryTypeToString(e.memType);
event["coreType"] = CoreClassToStr(e.coreLocation.coreType);
event["coreIdx"] = e.coreLocation.coreIdx;
event["requestSize"] = e.requestSize;
Json snap;
snap["capacity"] = e.capacity;
Json occupied = Json::array();
for (const auto& s : e.occupiedSlices) {
Json item;
item["memId"] = s.memId;
item["addrStart"] = s.addrStart;
item["addrEnd"] = s.addrEnd;
item["size"] = s.size;
item["ownerOpMagic"] = s.ownerOpMagic;
occupied.push_back(std::move(item));
}
snap["occupiedSlices"] = std::move(occupied);
Json freeIv = Json::array();
for (const auto& f : e.freeIntervals) {
Json item;
item["start"] = f.start;
item["size"] = f.size;
freeIv.push_back(std::move(item));
}
snap["freeIntervals"] = std::move(freeIv);
event["bufferSnapshot"] = std::move(snap);
timeline_.push_back(std::move(event));
}
void MemoryTracer::OnInitDDRBuffer(const InitDDRBufferEvent& e)
{
Json event;
event["eventType"] = "INIT_DDR_BUFFER";
event["clock"] = e.clock;
event["memId"] = e.memId;
event["kind"] = DDRKindToStr(e.kind);
event["magic"] = e.magic;
event["dtype"] = DataType2String(e.dtype);
event["shape"] = e.shape;
timeline_.push_back(std::move(event));
}
void MemoryTracer::OnScheduleEnd(const ScheduleEndEvent& e)
{
totalCycles_ = e.totalCycles;
succeeded_ = e.success;
ended_ = true;
}
Status MemoryTracer::Flush(const std::string& folderPath)
{
if (prefix_.empty()) return SUCCESS;
if (!ended_ && timeline_.empty()) return SUCCESS;
Json metadata;
metadata["totalCycles"] = totalCycles_;
metadata["scheduleResult"] = succeeded_ ? "SUCCESS" : "FAILED";
auto arch = Platform::Instance().GetSoc().GetNPUArch();
auto archStr = (arch == NPUArch::DAV_UNKNOWN) ? std::string(FALLBACK_ARCH) : NPUArchToString(arch);
metadata["chipArch"] = std::move(archStr);
Json doc;
doc["version"] = TRACE_VERSION;
doc["metadata"] = std::move(metadata);
doc["timeline"] = std::move(timeline_);
std::string traceFile = folderPath + "/" + prefix_ + "_OoO_Memory_Trace.json";
std::ofstream out(traceFile);
if (!out) {
APASS_LOG_WARN_F(Elements::Function, "MemoryTracer: cannot open %s for write.", traceFile.c_str());
return FAILED;
}
out << doc.dump(1) << std::endl;
out.close();
return SUCCESS;
}
}