← Design Verification Interviews
Interview Question · Debug
A Batched DPI Call That Got Slower
The Question
The interviewer asks
A teammate batched a per-byte CRC into one DPI call per packet to save time. The timing log says the batch is slower. Explain the numbers and say what you would change.
# 100000 packets of 64 bytes. Verilator 5.052, C++ built at -O0 (a debug build).
crc_byte one DPI call per byte 6400000 calls 114 ms
crc_packet one DPI call per packet 100000 calls 317 ms
# The same C file rebuilt at -O2.
crc_byte 48 ms
crc_packet 49 msYou have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
The crossing is not the cost here: Verilator turns an import into a direct C++ call. The batched version still calls svGetArrElemPtr1 once per byte, and at -O0 each call does full bounds checks. At -O2 both versions take the same time, so the CRC loop itself dominates. Take one pointer with svGetArrayPtr when it is not null, and build the model optimised. Profile on the sign-off simulator before changing the interface again.
Self-Check
Tick each key point you covered in your answer.
What Interviewers Listen For (Senior)
Reads both builds before blaming DPI and finds the per-element accessor. Asks for a profile on the sign-off simulator.
What Interviewers Listen For (Staff)
Notes that crossing costs differ between simulators, so performance rules must be measured per tool, not copied.
Cross-Questions
Where the interviewer goes next. Open a node to practise that follow-up.
WhyProve ItCompareScale It
- A Batched DPI Call That Got Slower
-
WhyWhy a DPI Call Is Cheap in VerilatorL3 Senior
Why is a DPI call so cheap in Verilator?
2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
Verilator compiles the whole testbench to C++. An import becomes a small generated wrapper that converts the arguments and calls your function in the same binary. Our backtrace shows that wrapper,
Vdpiimwrap_model_predict, as one frame. There is no interpreter between the two sides.Self-Check
Tick each key point you covered in your answer.
Half-Truth
"So DPI is cheap in every simulator."
Other simulators may add work at the boundary, such as converting values or saving context. Only a measurement on that tool tells you.
-
CompareWhat Argument Types Cost in a Hot LoopL3 Senior
Compare passing
logic [511:0],bit [511:0]and astringto C a million times in a loop.2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
In our -O0 probe, a million calls took 46 ms with
logic [511:0], 30 ms withbit [511:0]and 50 ms with a short string. A four-state vector carries two words for every 32 bits, so there is more to convert. A string may need a conversion toconst char*. In a hot path, prefer two-state types and numbers.Self-Check
Tick each key point you covered in your answer.
Half-Truth
"Use
logiceverywhere; it costs nothing extra."Each 32 bits of
logiccross as anavaland abvalword. That doubles the data the call must build. -
Prove ItMeasuring Where DPI Time GoesL3 Senior
Prove it: how do you show where the time goes before you change the model's interface?
2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
Run the simulator's profiler, or
perfon a compiled binary, and read the top functions. Count the calls into C per test. Then time the same calls with an empty C body. That time is the crossing, and the rest is the model's own work.Self-Check
Tick each key point you covered in your answer.
Half-Truth
"Time the whole test with and without the model."
That mixes the crossing, the model's work and any stimulus changes. It cannot tell you which part to fix.
-
Scale ItA Model Called on Every ClockL2 Mid-LevelL3 Senior
What if the C model is called from an
always @(posedge clk)block on every cycle, even when no transfer happens?2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
The call count now grows with simulated cycles, not with transactions. A long idle period costs as much as busy traffic. Call the model only when the protocol says a transfer happened, such as
valid && readyat the edge.Self-Check
Tick each key point you covered in your answer.
Half-Truth
"Return early from C on idle cycles, and it is free."
The call still happens, with its argument conversion, on every cycle. Gate the call in SystemVerilog instead.
What People Get Wrong
Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.
Misconception
"One DPI call per packet means one function call per packet."
The element accessor is a function call too. The twin counts 6400 accessor calls for 100 packets.
Run It
100 packets of 64 bytes through a batched CRC. A counter in C records each open-array accessor call.
DPI calls=100, accessor calls=6400, crc=100ece8c FAIL: the batched call still made one accessor call per byteSee the Fix
module tb;
import "DPI-C" function int unsigned crc_packet(input byte unsigned data[], input int count);
import "DPI-C" function int accessor_calls();
byte unsigned pkt[64];
int unsigned crc;
initial begin
foreach (pkt[i]) pkt[i] = i;
for (int p = 0; p < 100; p++) crc = crc_packet(pkt, 64);
$display("DPI calls=100, accessor calls=%0d, crc=%h", accessor_calls(), crc);
if (accessor_calls() > 100) $display("FAIL: the batched call still made one accessor call per byte");
else $display("PASS: one pointer per packet, so the per-byte calls are gone");
$finish;
end
endmodule
Prints: DPI calls=100, accessor calls=100, crc=100ece8c PASS: one pointer per packet, so the per-byte calls are gone
Tool as Truth
"DPI calls are nearly free; Verilator just proved it."
That is one compiled-code simulator. An event-driven simulator may convert arguments and save context on each call, so measure on the tool you sign off with.
Source Measured on a local Verilator 5.052 build with g++, 2026-11-08 (6.4 million per-byte calls cost 114 ms at -O0); Spear & Tumbush, SystemVerilog for Verification (3rd ed.), §12.7
Wrong Altitude
"Rewrite the CRC in SystemVerilog before measuring anything."
The -O2 numbers already show the CRC work, not the language boundary, sets the time. A rewrite guesses at a cause the log rules out.