From d1b6224c2bccee2db17fc648d0efc6bf7eb2e706 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Mon, 23 Oct 2023 16:01:55 +0100 Subject: [PATCH 1/2] Associate trace codes with function indices (#4610) For each traced variable, also register the trace function index that will write it. --- include/verilated_fst_c.cpp | 29 +++++++++++--------- include/verilated_fst_c.h | 14 +++++----- include/verilated_trace.h | 27 +++++++++++-------- include/verilated_trace_imp.h | 41 +++++++++++++++------------- include/verilated_vcd_c.cpp | 23 +++++++++------- include/verilated_vcd_c.h | 17 +++++++----- src/V3AstNodeOther.h | 5 +++- src/V3EmitCImp.cpp | 2 ++ src/V3Trace.cpp | 50 ++++++++++++++++++++++++----------- 9 files changed, 125 insertions(+), 83 deletions(-) diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 670b78b6b6..62623dbd84 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -222,35 +222,38 @@ void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum, fstVar } } -void VerilatedFst::declEvent(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum) { +void VerilatedFst::declEvent(uint32_t code, uint32_t fidx, const char* name, int dtypenum, + fstVarDir vardir, fstVarType vartype, bool array, int arraynum) { declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0); } -void VerilatedFst::declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum) { +void VerilatedFst::declBit(uint32_t code, uint32_t fidx, const char* name, int dtypenum, + fstVarDir vardir, fstVarType vartype, bool array, int arraynum) { declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0); } -void VerilatedFst::declBus(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum, int msb, int lsb) { +void VerilatedFst::declBus(uint32_t code, uint32_t fidx, const char* name, int dtypenum, + fstVarDir vardir, fstVarType vartype, bool array, int arraynum, int msb, + int lsb) { declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb); } -void VerilatedFst::declQuad(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum, int msb, int lsb) { +void VerilatedFst::declQuad(uint32_t code, uint32_t fidx, const char* name, int dtypenum, + fstVarDir vardir, fstVarType vartype, bool array, int arraynum, + int msb, int lsb) { declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb); } -void VerilatedFst::declArray(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum, int msb, int lsb) { +void VerilatedFst::declArray(uint32_t code, uint32_t fidx, const char* name, int dtypenum, + fstVarDir vardir, fstVarType vartype, bool array, int arraynum, + int msb, int lsb) { declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb); } -void VerilatedFst::declDouble(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum) { +void VerilatedFst::declDouble(uint32_t code, uint32_t fidx, const char* name, int dtypenum, + fstVarDir vardir, fstVarType vartype, bool array, int arraynum) { declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 63, 0); } //============================================================================= // Get/commit trace buffer -VerilatedFst::Buffer* VerilatedFst::getTraceBuffer() { +VerilatedFst::Buffer* VerilatedFst::getTraceBuffer(uint32_t fidx) { if (offload()) return new OffloadBuffer{*this}; return new Buffer{*this}; } diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index 57671e0d70..2f659db91b 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -74,7 +74,7 @@ class VerilatedFst final : public VerilatedTrace::runCallbacks(const std::vector mainThreadWorkerData; // Enqueue all the jobs - for (unsigned i = 0; i < cbVec.size(); ++i) { - const CallbackRecord& cbr = cbVec[i]; + for (const CallbackRecord& cbr : cbVec) { // Always get the trace buffer on the main thread - Buffer* const bufp = getTraceBuffer(); + Buffer* const bufp = getTraceBuffer(cbr.m_fidx); // Create new work item workerData.emplace_back(cbr.m_dumpCb, cbr.m_userp, bufp); // Grab the new work item ParallelWorkerData* const itemp = &workerData.back(); // Enqueue task to thread pool, or main thread - if (unsigned rem = i % threads) { + if (unsigned rem = cbr.m_fidx % threads) { threadPoolp->workerp(rem - 1)->addTask(parallelWorkerTask, itemp); } else { mainThreadWorkerData.push_back(itemp); @@ -530,7 +529,7 @@ void VerilatedTrace::runCallbacks(const std::vector::runOffloadedCallbacks( const std::vector& cbVec) { // Fall back on sequential execution for (const CallbackRecord& cbr : cbVec) { - Buffer* traceBufferp = getTraceBuffer(); + Buffer* traceBufferp = getTraceBuffer(cbr.m_fidx); cbr.m_dumpOffloadCb(cbr.m_userp, static_cast(traceBufferp)); commitTraceBuffer(traceBufferp); } @@ -704,28 +703,34 @@ void VerilatedTrace::addInitCb(initCb_t cb, void* userp) VL_ addCallbackRecord(m_initCbs, CallbackRecord{cb, userp}); } template <> -void VerilatedTrace::addConstCb(dumpCb_t cb, void* userp) VL_MT_SAFE { - addCallbackRecord(m_constCbs, CallbackRecord{cb, userp}); +void VerilatedTrace::addConstCb(dumpCb_t cb, uint32_t fidx, + void* userp) VL_MT_SAFE { + addCallbackRecord(m_constCbs, CallbackRecord{cb, fidx, userp}); } template <> -void VerilatedTrace::addConstCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE { - addCallbackRecord(m_constOffloadCbs, CallbackRecord{cb, userp}); +void VerilatedTrace::addConstCb(dumpOffloadCb_t cb, uint32_t fidx, + void* userp) VL_MT_SAFE { + addCallbackRecord(m_constOffloadCbs, CallbackRecord{cb, fidx, userp}); } template <> -void VerilatedTrace::addFullCb(dumpCb_t cb, void* userp) VL_MT_SAFE { - addCallbackRecord(m_fullCbs, CallbackRecord{cb, userp}); +void VerilatedTrace::addFullCb(dumpCb_t cb, uint32_t fidx, + void* userp) VL_MT_SAFE { + addCallbackRecord(m_fullCbs, CallbackRecord{cb, fidx, userp}); } template <> -void VerilatedTrace::addFullCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE { - addCallbackRecord(m_fullOffloadCbs, CallbackRecord{cb, userp}); +void VerilatedTrace::addFullCb(dumpOffloadCb_t cb, uint32_t fidx, + void* userp) VL_MT_SAFE { + addCallbackRecord(m_fullOffloadCbs, CallbackRecord{cb, fidx, userp}); } template <> -void VerilatedTrace::addChgCb(dumpCb_t cb, void* userp) VL_MT_SAFE { - addCallbackRecord(m_chgCbs, CallbackRecord{cb, userp}); +void VerilatedTrace::addChgCb(dumpCb_t cb, uint32_t fidx, + void* userp) VL_MT_SAFE { + addCallbackRecord(m_chgCbs, CallbackRecord{cb, fidx, userp}); } template <> -void VerilatedTrace::addChgCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE { - addCallbackRecord(m_chgOffloadCbs, CallbackRecord{cb, userp}); +void VerilatedTrace::addChgCb(dumpOffloadCb_t cb, uint32_t fidx, + void* userp) VL_MT_SAFE { + addCallbackRecord(m_chgOffloadCbs, CallbackRecord{cb, fidx, userp}); } template <> void VerilatedTrace::addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE { diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index fc0b438cb4..282052528d 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -520,32 +520,35 @@ void VerilatedVcd::declare(uint32_t code, const char* name, const char* wirep, b m_namemapp->emplace(hiername, decl); } -void VerilatedVcd::declEvent(uint32_t code, const char* name, bool array, int arraynum) { +void VerilatedVcd::declEvent(uint32_t code, uint32_t fidx, const char* name, bool array, + int arraynum) { declare(code, name, "event", array, arraynum, false, false, 0, 0); } -void VerilatedVcd::declBit(uint32_t code, const char* name, bool array, int arraynum) { +void VerilatedVcd::declBit(uint32_t code, uint32_t fidx, const char* name, bool array, + int arraynum) { declare(code, name, "wire", array, arraynum, false, false, 0, 0); } -void VerilatedVcd::declBus(uint32_t code, const char* name, bool array, int arraynum, int msb, - int lsb) { +void VerilatedVcd::declBus(uint32_t code, uint32_t fidx, const char* name, bool array, + int arraynum, int msb, int lsb) { declare(code, name, "wire", array, arraynum, false, true, msb, lsb); } -void VerilatedVcd::declQuad(uint32_t code, const char* name, bool array, int arraynum, int msb, - int lsb) { +void VerilatedVcd::declQuad(uint32_t code, uint32_t fidx, const char* name, bool array, + int arraynum, int msb, int lsb) { declare(code, name, "wire", array, arraynum, false, true, msb, lsb); } -void VerilatedVcd::declArray(uint32_t code, const char* name, bool array, int arraynum, int msb, - int lsb) { +void VerilatedVcd::declArray(uint32_t code, uint32_t fidx, const char* name, bool array, + int arraynum, int msb, int lsb) { declare(code, name, "wire", array, arraynum, false, true, msb, lsb); } -void VerilatedVcd::declDouble(uint32_t code, const char* name, bool array, int arraynum) { +void VerilatedVcd::declDouble(uint32_t code, uint32_t fidx, const char* name, bool array, + int arraynum) { declare(code, name, "real", array, arraynum, false, false, 63, 0); } //============================================================================= // Get/commit trace buffer -VerilatedVcd::Buffer* VerilatedVcd::getTraceBuffer() { +VerilatedVcd::Buffer* VerilatedVcd::getTraceBuffer(uint32_t fidx) { VerilatedVcd::Buffer* const bufp = new Buffer{*this}; if (parallel()) { // Note: This is called from VerilatedVcd::dump, which already holds the lock diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 9ffceaa876..1e0ddcec40 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -107,7 +107,7 @@ class VerilatedVcd VL_NOT_FINAL : public VerilatedTracecode())); if (nodep->arrayRange().ranged()) puts("+i*" + cvtToStr(nodep->widthWords())); puts(","); + puts(cvtToStr(nodep->fidx())); + puts(","); putsQuoted(VIdProtect::protectWordsIf(nodep->showname(), nodep->protect())); // Direction if (v3Global.opt.traceFormat().fst()) { diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 58cbad7245..a7bc4fa423 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -477,22 +477,28 @@ class TraceVisitor final : public VNVisitor { } } - AstCFunc* newCFunc(VTraceType traceType, AstCFunc* topFuncp, unsigned funcNum, + AstCFunc* newCFunc(VTraceType traceType, AstCFunc* topFuncp, uint32_t funcNum, uint32_t baseCode = 0) { // Create new function const bool isTopFunc = topFuncp == nullptr; - std::string baseName = "trace_"; - if (traceType == VTraceType::CONSTANT) { - baseName += "const_"; - } else if (traceType == VTraceType::FULL) { - baseName += "full_"; + std::string funcName; + if (isTopFunc) { + if (traceType == VTraceType::CONSTANT) { + funcName = "trace_const"; + } else if (traceType == VTraceType::FULL) { + funcName = "trace_full"; + } else { + funcName = "trace_chg"; + } } else { - baseName += "chg_"; + funcName = topFuncp->name(); + funcName += "_sub"; } - baseName += isTopFunc ? "top_" : "sub_"; + funcName += "_"; + funcName += cvtToStr(funcNum); FileLine* const flp = m_topScopep->fileline(); - AstCFunc* const funcp = new AstCFunc{flp, baseName + cvtToStr(funcNum), m_topScopep}; + AstCFunc* const funcp = new AstCFunc{flp, funcName, m_topScopep}; funcp->isTrace(true); funcp->dontCombine(true); funcp->isLoose(true); @@ -526,6 +532,8 @@ class TraceVisitor final : public VNVisitor { } m_regFuncp->addStmtsp(new AstText{flp, str, true}); m_regFuncp->addStmtsp(new AstAddrOfCFunc{flp, funcp}); + m_regFuncp->addStmtsp(new AstText{flp, ", ", true}); + m_regFuncp->addStmtsp(new AstConst{flp, funcNum}); m_regFuncp->addStmtsp(new AstText{flp, ", vlSelf);\n", true}); } else { // Sub functions @@ -565,7 +573,7 @@ class TraceVisitor final : public VNVisitor { : std::numeric_limits::max(); AstCFunc* const topFuncp = newCFunc(VTraceType::CONSTANT, nullptr, 0); - unsigned subFuncNum = 0; + uint32_t subFuncNum = 0; AstCFunc* subFuncp = nullptr; int subStmts = 0; for (auto it = traces.cbegin(); it != traces.end(); ++it) { @@ -612,14 +620,16 @@ class TraceVisitor final : public VNVisitor { uint32_t parallelism) { const int splitLimit = v3Global.opt.outputSplitCTrace() ? v3Global.opt.outputSplitCTrace() : std::numeric_limits::max(); - unsigned topFuncNum = 0; - unsigned subFuncNum = 0; + + // pre-incremented, so starts at 0 + uint32_t topFuncNum = std::numeric_limits::max(); TraceVec::const_iterator it = traces.begin(); while (it != traces.end()) { AstCFunc* topFulFuncp = nullptr; AstCFunc* topChgFuncp = nullptr; AstCFunc* subFulFuncp = nullptr; AstCFunc* subChgFuncp = nullptr; + uint32_t subFuncNum = 0; int subStmts = 0; const uint32_t maxCodes = std::max((nAllCodes + parallelism - 1) / parallelism, 1U); uint32_t nCodes = 0; @@ -627,20 +637,25 @@ class TraceVisitor final : public VNVisitor { AstIf* ifp = nullptr; uint32_t baseCode = 0; for (; nCodes < maxCodes && it != traces.end(); ++it) { - const TraceTraceVertex* const vtxp = it->second; - // This is a duplicate decl, no need to add it - if (vtxp->duplicatep()) continue; const ActCodeSet& actSet = it->first; // Traced value never changes, no need to add it if (actSet.count(TraceActivityVertex::ACTIVITY_NEVER)) continue; + const TraceTraceVertex* const vtxp = it->second; AstTraceDecl* const declp = vtxp->nodep(); + // This is a duplicate decl, no need to add it, but must set the + // function index to the same as the canonical node. + if (const TraceTraceVertex* const canonVtxp = vtxp->duplicatep()) { + declp->fidx(canonVtxp->nodep()->fidx()); + continue; + } + // Create top function if not yet created if (!topFulFuncp) { + ++topFuncNum; topFulFuncp = newCFunc(VTraceType::FULL, nullptr, topFuncNum); topChgFuncp = newCFunc(VTraceType::CHANGE, nullptr, topFuncNum); - ++topFuncNum; } // Create new sub function if required @@ -682,6 +697,9 @@ class TraceVisitor final : public VNVisitor { = new AstTraceInc{flp, declp, VTraceType::CHANGE, baseCode}; ifp->addThensp(incChgp); + // Set the function index of the decl + declp->fidx(topFuncNum); + // Track splitting due to size UASSERT_OBJ(incFulp->nodeCount() == incChgp->nodeCount(), declp, "Should have equal cost"); From 17721aff556c387956c47485308f6a91c549d73a Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Tue, 24 Oct 2023 10:01:41 +0100 Subject: [PATCH 2/2] Remove unused IMPLICITWIRE var type --- src/V3Ast.h | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 79fdfd3e36..1f58b767f2 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -822,7 +822,6 @@ class VVarType final { SUPPLY1, WIRE, WREAL, - IMPLICITWIRE, TRIWIRE, TRI0, TRI1, @@ -842,26 +841,25 @@ class VVarType final { : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning constexpr operator en() const { return m_e; } const char* ascii() const { - static const char* const names[] = { - "?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1", - "WIRE", "WREAL", "IMPLICITWIRE", "TRIWIRE", "TRI0", "TRI1", "PORT", - "BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"}; + static const char* const names[] + = {"?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1", + "WIRE", "WREAL", "TRIWIRE", "TRI0", "TRI1", "PORT", "BLOCKTEMP", + "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"}; return names[m_e]; } bool isParam() const { return m_e == GPARAM || m_e == LPARAM; } bool isSignal() const { - return (m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 - || m_e == TRI1 || m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR); + return (m_e == WIRE || m_e == WREAL || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 + || m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR); } bool isNet() const { - return (m_e == WIRE || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 - || m_e == SUPPLY0 || m_e == SUPPLY1); + return (m_e == WIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 || m_e == SUPPLY0 + || m_e == SUPPLY1); } bool isContAssignable() const { // In Verilog, always ok in SystemVerilog - return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL - || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 - || m_e == PORT || m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP - || m_e == XTEMP || m_e == IFACEREF); + return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL || m_e == TRIWIRE + || m_e == TRI0 || m_e == TRI1 || m_e == PORT || m_e == BLOCKTEMP + || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP || m_e == IFACEREF); } bool isProcAssignable() const { return (m_e == GPARAM || m_e == LPARAM || m_e == GENVAR || m_e == VAR || m_e == BLOCKTEMP