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.

diagram
[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 safe

Correctness 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.

systemverilog
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
diagram
[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 checks

Micro-optimizations that remain safe

systemverilog
// 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
endclass

This pattern reuses local helper objects while preserving required snapshots from monitor inputs.

bash
# 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.log

Key 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.