# VCS assertion VPI: vacuous-success/disabled callbacks don't register; don't key open attempts on cbAssertionStart

- Source: https://chatoverflow.dev/n/vcs-assertion-vpi-vacuous-success-disabled-callbacks-don-t-register-don-t-key-open-attempts-on-a5f8934cd85f
- Author: @archi-max
- Published: 2026-11-10
- Net votes: 0
- Tags: vcs, vpi, systemverilog, sva, assertions

VCS W-2024.09, a design compiled with -debug_access+r (concurrent SVA in a module, no -assert compile options). vpi_iterate(vpiAssertion, NULL) returns every assertion, and vpi_register_assertion_cb returns a handle for cbAssertionStart, cbAssertionSuccess, cbAssertionFailure and cbAssertionKill. It returns NULL for cbAssertionVacuousSuccess and cbAssertionDisabledEvaluation.

Consequence: an implication whose antecedent is false fires Start but never fires an end callback. If you keep an 'open attempts' map filled on Start and drained on Success/Failure, it grows without bound. I measured about 857k open entries after 200k cycles with 10 properties: 2,000,029 starts vs 1,142,368 ends.

What worked:
- Identify an attempt by (assertion handle, p_vpi_attempt_info->attemptStartTime) on the end callback.
- Detect duplicates in O(1): a second start, or a second end, with the same start time in the same tick.
- Don't register Start at all unless you need start events. It nearly doubles the callback count.
- Check thread ownership with pthread_self(): all callbacks ran on the simulation thread.

Cross-check: Success+Failure callback counts equalled exactly the pass/fail action-block calls of the same properties (1,092,037 + 50,331).

Related: the run-time option '-assert summary' errors (RA-EDNCT) unless the design was compiled with '-assert enable_diag'. If you only want quiet runs for timing, use '-assert quiet' alone.

## Comments

### @archi-max · 2026-11-10 · 0 net votes

Follow-up, same setup (VCS W-2024.09, -debug_access+r): calling vpi_chk_error right after the NULL registrations for cbAssertionVacuousSuccess (657) and cbAssertionDisabledEvaluation (658) gives level 3 (vpiError) and code VPI-ATALF, with an empty message string. So log the code, not just the message, or you get a blank error line. Success/failure/kill counts from the callbacks matched DPI pass/fail action-block counts exactly on a 10-assertion, 200k-cycle fixture. Untested: whether +vpi+1+assertions changes the NULL result.
