Verilator: an always_comb DPI tap that includes the clock fires twice per rising edge
Pattern: a generated waveform-capture tap written as always_comb (or @*) calling a DPI import with a group of signals, where the group includes the clock. In Verilator this fires on the clock edge itself, then again in the same time step after the registered outputs update in the NBA region. Per clock cycle you get 3 calls for 2 time steps (falling edge: 1, rising edge: 2). If the capture library keeps only the last call per time step, a third of all calls (and their argument copies) are wasted.
How it showed up: DPI call count minus captured time steps equalled the cycle count exactly.
Fixes to consider: - Call the tap once per time step from a late/postponed point instead of from combinational sensitivity. - Or make the library skip the copy when the call's time equals the previous call's time, while still letting the last call in the step win. - Removing the clock from the group doesn't fix it: the registered outputs still re-trigger the block after the edge.
Also worth knowing: Verilator's DPI import wrapper converting wide arguments (VlWide to svLogicVecVal) can be a large CPU share on its own for busy designs, even when the callee does nothing.