Part 10 · Advanced Topics · Intermediate
Object Churn and Field Automation
Control allocation, clone/copy overhead, and heavy field automation costs in high-throughput transactions.
Allocation churn in hot paths
Creating and discarding many transient sequence items or analysis snapshots can cause significant allocator pressure. Some cloning is necessary for correctness, but unnecessary deep copies should be avoided in high-frequency loops.
[PERF] object churn patterns
costly:
create -> copy -> compare -> discard per beat
repeated deep clone of large arrays
better:
clone only when ownership boundary requires snapshot
reuse scratch objects in local compare helpers
keep immutable fields shared where safeCorrectness vs performance boundary
Do not remove cloning at monitor->scoreboard boundaries where object reuse exists. Instead, optimize inside compare/transform steps and avoid redundant second copies.
Field automation cost model
Broad uvm_field_* macros with UVM_ALL_ON on very large payload arrays can inflate copy/print/pack cost. Use focused flags and custom do_print/do_compare for heavy fields when needed.
class pkt_txn extends uvm_sequence_item;
rand bit [31:0] addr;
rand byte payload[];
bit err;
`uvm_object_utils_begin(pkt_txn)
`uvm_field_int(addr, UVM_DEFAULT)
// Heavy payload: do not always print/record/pack by default
`uvm_field_array_int(payload, UVM_NOCOMPARE | UVM_NOPRINT)
`uvm_field_int(err, UVM_DEFAULT)
`uvm_object_utils_end
function bit do_compare(uvm_object rhs, uvm_comparer comparer);
pkt_txn other;
if (!$cast(other, rhs)) return 0;
if (addr != other.addr) return 0;
if (err != other.err) return 0;
// Compare payload only when enabled
if (comparer.show_max > 0) begin
if (payload.size() != other.payload.size()) return 0;
foreach (payload[i]) if (payload[i] != other.payload[i]) return 0;
end
return 1;
endfunction
endclass[PERF] field flag guidance
UVM_ALL_ON:
convenient but expensive for large fields
selective flags:
UVM_DEFAULT for key scalar fields
UVM_NOPRINT for bulk data
custom do_compare for targeted checksMicro-optimizations that remain safe
// Example: avoid repeated create in helper path
class scb_compare_helper extends uvm_object;
`uvm_object_utils(scb_compare_helper)
pkt_txn scratch_exp;
pkt_txn scratch_act;
function new(string name="scb_compare_helper");
super.new(name);
scratch_exp = pkt_txn::type_id::create("scratch_exp");
scratch_act = pkt_txn::type_id::create("scratch_act");
endfunction
function bit compare_pkt(pkt_txn exp, pkt_txn act);
scratch_exp.copy(exp);
scratch_act.copy(act);
return scratch_act.compare(scratch_exp);
endfunction
endclassThis pattern reuses local helper objects while preserving required snapshots from monitor inputs.
# Measure allocation-sensitive difference on fixed test/seed
simv_A +UVM_TESTNAME=packet_stress_test +ntb_random_seed=91355 -l out/logs/churn_A.log
simv_B +UVM_TESTNAME=packet_stress_test +ntb_random_seed=91355 -l out/logs/churn_B.logKey takeaways
Keep boundary cloning for correctness; trim redundant internal copies.
Use selective field automation flags on large payload fields.
Prefer custom compare/print methods for heavy transaction structures.
Validate allocation-oriented changes with fixed-seed A/B runs.
Common pitfalls
Removing required snapshots and introducing aliasing bugs.
Using UVM_ALL_ON on huge arrays in hot paths.
Applying micro-optimizations without checking correctness regressions.