Debugging and measuring with DOCA Bench
S3·E5Thirty percent, and a quote due tomorrow · Escalation bridge, dialed in from the lab, 21:10
Builds on: First programs: dma_copy and secure_channel
Before you read: what do you already know?
3 quick questions. Wrong answers are fine and expected; trying first makes the lesson stick.
After this lesson you can
- Set application and SDK log levels with -l and --sdk-log-level on the 10 to 70 numeric scale and justify when TRACE requires a trace build.
- Apply the five-rung debug ladder (environment, device, capability, state, task) to a failing DOCA program and name the first read-only probe at each rung.
- Run doca_bench for a DMA pipeline in throughput, bulk-latency and precision-latency modes and save the results as CSV.
- Evaluate a benchmark claim by checking whether two runs used comparable mode, step, job size, cores, run limit, flavor and DOCA version.
Episode 5 — Thirty percent, and a quote due tomorrow
Eleven people are on the bridge and only one number is being discussed: the archive’s perf lead says their BlueField-3 does thirty percent less DMA throughput than the figure in NVIDIA’s material. The procurement person, who in five weeks has asked about nothing but lead time, is on the call because the quote goes out in the morning and the PoC report is due Friday. Two people have already proposed swapping the card. Nobody has yet said what command produced the customer’s number — and the network lead, notebook three-quarters full, asks the only useful question on the bridge: show me the counter.
DOCA Bench exists so that this argument can be settled with evidence instead of seniority. It “allows users to evaluate the performance of DOCA applications, with reasonable accuracy for real-world applications”, ships under /opt/mellanox/doca/tools on both the host and the Arm image, and drives every engine through one CLI; with --csv-output-file it writes not only the stat but the configuration values used to produce it.[5] That last property is the whole point: a run that cannot be described in flags cannot be compared.
The two most common reasons a real number comes in low are not the card. A trace-flavor library “adds runtime input-sanitation and emits additional log lines” and costs performance, and the samples build in debug by default while DOCA ships release binaries.[3][2]
A number without its flags is a rumor.
So before the number, you ask about the two streams of output already scrolling on their screen.
1Two log streams, one numeric scale
Every DOCA program that uses ArgP inherits the same flags: -h/--help, -v/--version, -l/--log-level for the application, --sdk-log-level which “Sets the SDK numeric log level using the same 10-70 scale”, --log-filter which “Filters logs from specific modules (comma-separated list)”, and -j/--json to read flags from a file.[1] The scale is 10 DISABLE, 20 CRITICAL, 30 ERROR, 40 WARNING, 50 INFO, 60 DEBUG, 70 TRACE, where TRACE “requires compilation with TRACE support”.[1] One published NVIDIA skills file describes 30 as INFO; the Arg Parser page is the authority and says 30 is ERROR and 50 is INFO.[3][1]
The two streams come from two backends. dma_local_copy_main.c registers doca_log_backend_create_standard() for the sample’s own DOCA_LOG_* calls, then doca_log_backend_create_with_file_sdk(stderr, &sdk_log) and doca_log_backend_set_sdk_level(sdk_log, DOCA_LOG_LEVEL_WARNING) so SDK internals start at WARNING; modules are named with DOCA_LOG_REGISTER(DPU_LOCAL_DMA_COPY::MAIN), which is what --log-filter matches on.[6] ArgP itself has a fixed sequence: doca_argp_init() “must be the first function called”, then doca_argp_param_create with the short name, long name, description, callback and type setters and doca_argp_register_param, then doca_argp_start(argc, argv) and doca_argp_destroy().[1] A running program can also move its limits at runtime; the log_limits_server sample exposes doca_log_level_set_global_lower_limit and doca_log_level_set_global_upper_limit, with its client documenting “60 = DEBUG” and “20 = CRIT”.[9] A DOCA_LOG_LEVEL environment variable is honored only by “programs that read it”, so do not assume it.[3]
2TRACE needs a trace build
The 70 level is a compile-time feature. The samples README explains that enabling TRACE “activates various developer log messages left out of the release compilation”, switched on with enable_trace_log in meson_options.txt or on the command line as meson /tmp/build -Denable_trace_log=true.[2] In applications/meson.build that option becomes add_project_arguments('-DDOCA_LOGGING_ALLOW_TRACE', ...).[11] The same README reminds you that the default meson buildtype is debug and the binaries DOCA ships are release.[2]
The libraries have their own flavor. The setup notes describe a trace flavor under /opt/mellanox/doca/lib/<arch>-linux-gnu/trace/ that “adds runtime input-sanitation and emits additional log lines at DEBUG / TRACE level”, while the release flavor “does not emit those lines no matter how high you set --sdk-log-level”.[4][3] You select it either by linking pkg-config doca-<library>-trace instead of doca-<library>, or at run time with LD_LIBRARY_PATH=/opt/mellanox/doca/lib/<arch>-linux-gnu/trace:$LD_LIBRARY_PATH; pkg-config --exists doca-flow-trace tells you whether the flavor is installed.[3][10] Never edit the files under /opt/mellanox/doca/lib*/ to swap flavors.[10] The trace flavor has measurable overhead, so switch back to release before any performance measurement.[3]
3The debug ladder
The debugging notes order the layers install, version, build, link, runtime, program, driver and firmware, with one rule: “always start at the lowest layer the symptom is consistent with”.[3] For a program that already builds and links, this course folds them into five rungs. Environment: pkg-config --modversion doca-<library> and /opt/mellanox/doca/tools/doca_caps --version on both sides, because headers from one DOCA version against another runtime “returns DOCA_ERROR_INVALID_VALUE from a call that should never fail”.[3][8] Device: doca_caps --list-devs, ip link show, devlink dev show, dmesg | tail -200, journalctl --since "5 min ago"; the sample helper’s DOCA_ERROR_NOT_FOUND with “Matching device not found” lives here.[3] Capability: a doca_<library>_cap_* query or DOCA_ERROR_NOT_SUPPORTED, which the Core guide attributes to an API “not implemented for that processor”.[7][3] State: DOCA_ERROR_BAD_STATE is a call-order bug, DOCA_ERROR_IN_PROGRESS from a stop is normal, and --sdk-log-level 60 with a state-changed callback shows the transitions.[3][7] Task: the error callback’s doca_task_get_status, the flushed-versus-real distinction, and doca_task_try_submit to validate inputs during development.[9]
Before any change, collect the read-only triple: the program’s output with --sdk-log-level 70 on a trace build, the system view from dmesg and journalctl, and the DOCA view from doca_caps --list-devs and pkg-config --modversion.[3] Two cautions from the same notes: attaching gdb pauses the process, which trips watchdogs on server workloads, and inside the NGC container dmesg and journalctl show only the container’s view.[3] Never retry-loop INVALID_VALUE, BAD_STATE, NOT_SUPPORTED, INITIALIZATION or DRIVER; a task failure that moves the context to Stopping must be drained by progressing the PE before restart.[3][7] When the ladder ends in the driver or firmware, escalate through the DOCA developer forum with the triple attached.[3]
Dev / environment: build, capabilities, performance
4DOCA Bench: one CLI for every engine
“NVIDIA DOCA Bench allows users to evaluate the performance of DOCA applications, with reasonable accuracy for real-world applications”; it is installed under /opt/mellanox/doca/tools on both DOCA-Host and the BlueField Arm image and requires DOCA 2.7.0 or later.[5] The device is --device or -A, given as a PCIe address such as 03:00.0, an IB name such as mlx5_0, or an interface name such as ens4f0; from the Arm side target the local PCIe address.[5] The work is --pipeline-steps, a comma-separated list drawn from doca_compress::compress, doca_compress::decompress, doca_dma, doca_ec::create, doca_ec::recover, doca_ec::update, doca_sha, doca_rdma::send, doca_rdma::receive, doca_rdma::bidir, doca_aes_gcm::encrypt, doca_aes_gcm::decrypt, doca_cc::client_producer, doca_cc::client_consumer, doca_eth::rx, doca_eth::tx and the doca_gpunetio::* steps; note that the Comm Channel name doca_cc survives in Bench.[5]
--mode defaults to throughput, which “tries to keep each component under test as busy as possible”; bulk-latency submits batches and reports the time from the first submission to the last response in 100 buckets sized by --latency-bucket-range (for example 10us,100us; default 100ms,10ms); precision-latency “executes one job at a time” and “only supports job limited execution”.[5] Input is --data-provider with file, file-set or random-data, sized by --uniform-job-size in bytes, with --job-output-buffer-size (default 16384) and --data-provider-job-count (default 128 per thread).[5] Cores are --core-mask (default 0x02, at most 32 CPUs), --core-list such as 0,3,6-10, --core-count, and --threads-per-core.[5] Limits are --run-limit-seconds/-s, --run-limit-jobs/-J, --run-limit-bytes/-b.[5] Batching with --batch-mode and --batch-size applies only to doca_sha and doca_dma in throughput mode.[5]
Output goes to the console and, with --csv-output-file <path>, to a CSV containing stats and the configuration values; --csv-stats "stats.*" filters columns, --csv-append-mode appends across runs, --rt-stats-interval <ms> prints transient snapshots, and --sweep runs a range of values one line per iteration.[5] Discovery is --query device-capabilities (needs --device) and --query sweep-properties.[5] Remote memory for DMA uses the companion agent through --companion-connection-string with --use-remote-input-buffers or --use-remote-output-buffers.[5]
doca_bench --device 03:00.0 --pipeline-steps doca_dma \
--data-provider random-data --uniform-job-size 4096 \
--core-list 1-4 --threads-per-core 2 \
--mode throughput --run-limit-seconds 10 \
--csv-output-file /tmp/dma_throughput.csv5Evaluating a number
Two DOCA Bench results are comparable only when the inputs that define the work match: the same --mode, the same --pipeline-steps, the same --uniform-job-size and data provider, the same --core-list or --core-mask with the same --threads-per-core, the same run limit, and the same choice of local versus remote buffers.[5] The CSV is the evidence, because it “can contain stats and the configuration values used to produce that stat”.[5] Then the environment: a release-flavor library and a release buildtype, since trace and debug both cost performance, and identical DOCA versions on the machines being compared.[3][2][8] Bench itself notes that doca_dma and doca_sha “execute in constant time regardless of the input data” while compression depends on data, so data provider matters more for some steps than others.[5]
Measure DMA three ways on one device and keep every other flag constant:
B="doca_bench --device 03:00.0 --pipeline-steps doca_dma --data-provider random-data --uniform-job-size 4096 --core-list 1-4 --threads-per-core 2"
$B --mode throughput --run-limit-seconds 10 --csv-output-file /tmp/dma_tp.csv
$B --mode bulk-latency --run-limit-seconds 10 --latency-bucket-range 10us,100us --csv-output-file /tmp/dma_bl.csv
$B --mode precision-latency --run-limit-jobs 10000 --csv-output-file /tmp/dma_pl.csvReading: throughput reports bandwidth and job rate; bulk-latency adds a histogram whose first bucket is everything faster than 10us and whose last bucket is everything slower than the range; precision-latency reports the minimum and distribution per job at greatly reduced throughput. All three share device, step, job size, cores and threads, so a difference between them is the mode and nothing else. The three CSVs carry the flags, so anyone can verify that later.
- Throughput:
doca_bench --device ____ --pipeline-steps ____ --data-provider random-data --uniform-job-size 4096 --mode ____ --run-limit-seconds 10 --csv-output-file ____. - Bulk latency: same flags with
--mode ____ --latency-bucket-range ____. - Precision latency: same flags with
--mode ____and a job limit____ 10000because that mode supports only ____ execution. - Before comparing to any published figure, confirm the library flavor is ____ and the build type is ____.
A customer sends one line: “Our BlueField-3 in the R7725 does 30 percent less DMA throughput than NVIDIA’s number.” Write the list of items you require before accepting the claim, run your own three-mode measurement on the lab card, and produce a one-page comparison.
Acceptance criteria: your request names at least these seven items: full doca_bench command line, the CSV, --mode, --uniform-job-size, core list and threads per core, library flavor and buildtype, and doca_caps --version output from host and Arm; your own runs share every flag except --mode; your comparison states explicitly whether the customer’s run is comparable and, if not, which flag makes it incomparable.
Episode 5 — Case closed: the flag that explained it
Their LD_LIBRARY_PATH pointed at a trace directory, and the binary was a default meson build — debug, not release.[3][2] Rebuilt release, run against release libraries with the same job size, core list and mode, the gap closes. Both CSVs go into the PoC report.[5]
What you say on the bridge: “Send me the command line and the CSV, not the number. Nine times out of ten it is in the configuration columns.”
The report ships Friday; the purchase order for the 32 nodes follows. The SE closes the last row of the promise spreadsheet and drinks his coffee cold. In the lab a sticker still reads START ME FIRST, and the network lead’s notebook — the counters, the two-column CPU page, the flags — is now the archive’s bring-up runbook.
Lab
Pre-flight (read-only): /opt/mellanox/doca/tools/doca_caps --version on host and Arm must match; /opt/mellanox/doca/tools/doca_caps --list-devs on the Arm for the PF address. Confirm you are using the shipped release doca_bench, not a trace build.
- On the Arm side:
/opt/mellanox/doca/tools/doca_bench --device <pf> --query device-capabilities— expect a per-library table includingdoca_dmamarked capable and supported. - Throughput:
doca_bench --device <pf> --pipeline-steps doca_dma --data-provider random-data --uniform-job-size 4096 --core-list 1-4 --threads-per-core 2 --mode throughput --run-limit-seconds 10 --csv-output-file /tmp/dma_tp.csv— expect a bandwidth and job-rate summary and a CSV file. If Bench reports the core list is invalid, usenprocand pick cores that exist. - Bulk latency: same flags with
--mode bulk-latency --latency-bucket-range 10us,100us --csv-output-file /tmp/dma_bl.csv— expect a histogram whose buckets are 100us wide. - Precision latency: same flags with
--mode precision-latency --run-limit-jobs 10000 --csv-output-file /tmp/dma_pl.csv— expect per-job minimum and percentiles; if you passed--run-limit-secondsby mistake, Bench rejects it because this mode is job-limited only. head -3 /tmp/dma_tp.csv— expect a header row that includes configuration columns; copy the three CSVs to your notes. Log-level check:/tmp/build-dma/doca_dma_local_copy -p <pf> --sdk-log-level 60 -l 60— expect SDK DEBUG lines interleaved with the state-change messages.- Rollback: none required; Bench generates DMA traffic against process memory and changes no device configuration. Kill a run with Ctrl-C if it exceeds its limit.
- In the
devel-3.5.0-hostcontainer:/tmp/build-dma/doca_dma_local_copy --help— expect-l/--log-level,--sdk-log-level,--log-filter,-j/--jsonalongside the sample’s own flags. These are the ArgP standard flags. - Rebuild the sample as a trace build:
meson /tmp/build-dma-trace -Denable_trace_log=true && ninja -C /tmp/build-dma-trace. Thenpkg-config --exists doca-dma-trace; echo $?— expect0if the trace flavor is installed in the image; if1, note that SDK trace lines will not be available here regardless of--sdk-log-level. grep -rn "DOCA_LOG_TRC\|DOCA_LOGGING_ALLOW_TRACE" applications/meson.build samples/doca_dma/ | head— expect the define inapplications/meson.buildand anyDOCA_LOG_TRCuses in the samples./opt/mellanox/doca/tools/doca_bench --help | head -80— expect the flags from segment 4. Then/opt/mellanox/doca/tools/doca_bench --query sweep-properties— expect a list of sweepable attributes.--query device-capabilitiesrequires--deviceand cannot succeed without hardware; confirm the error message names the device.- Ladder drill without hardware: run
/tmp/build-pe/doca_pe_event(built in lesson 3.3; it takes no arguments and picks the first DMA-capable device itself) — expectMatching device not foundfromopen_doca_device_with_capabilitiesinsamples/common.c, which is the device rung. Then run the host build/tmp/build-dma/doca_dma_local_copy -p 03:00.0 --sdk-log-level 60— expectLocal DMA copy can run only on the DPU, which is the environment/build rung (the#ifndef DOCA_ARCH_DPUguard fires before any device is opened).[6] Name which rung each message belongs to and what the next read-only probe would be on a real host. - Draft the seven-item request list from the Worked problem as a reusable text snippet.
Retrieval check
9 questions from memory. Answer before looking anything up; misses become flashcards.
Explain it to a Dell SE
Explain to a Dell SE, in five sentences, how you would decide whether a customer's DOCA Bench numbers show a real problem with their PowerEdge and BlueField-3 or a measurement mistake.
Sources
Facts in this lesson were checked against DOCA 3.5.0 Arg Parser and DOCA Bench pages, doca-samples tag 3.5.0, 2026-09-06. Dates are when each page was fetched.
- DOCA Arg Parser (standard flags and log levels) · fetched 2026-09-06 · DOCA 3.5.0
- doca-samples README (trace build) · fetched 2026-09-06 · DOCA 3.5.0
- NVIDIA/skills doca-debug CAPABILITIES.md · fetched 2026-09-06 · DOCA 3.5.0
- NVIDIA/skills doca-setup CAPABILITIES.md (trace flavor) · fetched 2026-09-06 · DOCA 3.5.0
- DOCA Bench · fetched 2026-09-06 · DOCA 3.5.0
- dma_local_copy_main.c (log backends) · fetched 2026-09-06 · DOCA 3.5.0
- DOCA Core programming guide (error codes, ctx errors) · fetched 2026-09-06 · DOCA 3.5.0
- NVIDIA/skills doca-version CAPABILITIES.md · fetched 2026-09-06 · DOCA 3.5.0
- samples/doca_common/README.md (try_submit, log limits) · fetched 2026-09-06 · DOCA 3.5.0
- NVIDIA/skills doca-programming-guide CAPABILITIES.md · fetched 2026-09-06 · DOCA 3.5.0
- applications/meson.build (DOCA_LOGGING_ALLOW_TRACE) · fetched 2026-09-06 · DOCA 3.5.0
The same idea elsewhere
Other lessons that cover this ground, sometimes from another course's angle.