Skip to content

Add unit tests, CI, lint targets; fix example arg parser and GiB/s naming - #1

Merged
staryxchen merged 6 commits into
mainfrom
add-tests-ci-and-fixes
Jul 10, 2026
Merged

Add unit tests, CI, lint targets; fix example arg parser and GiB/s naming#1
staryxchen merged 6 commits into
mainfrom
add-tests-ci-and-fixes

Conversation

@staryxchen

Copy link
Copy Markdown
Owner

Summary

Adds unit test infrastructure, CI, and lint/format tooling, plus fixes two deferred code issues and brings docs up to date. All work is behavior-preserving except the two called-out bug fixes.

Changes

Build & tooling

  • Makefile fix: use /usr/local/cuda symlink (was hardcoded cuda-12.9); add NVML include path to the monitor build.
  • Lint/format targets: make format (apply clang-format in place) and make check-format (--dry-run --Werror, CI gate).
  • CI (.github/workflows/ci.yml): runs make check-format + make test on ubuntu-22.04 for push/PR. No GPU needed — the test binary links only extracted pure-logic modules + gtest, with no NVML/CUDA library symbols.

Unit tests (GoogleTest 1.11.0, 52 tests, no GPU required)

Extracted pure-logic functions into testable translation units (mirrored monitor/arg_parser pattern for both binaries):

  • monitor/bandwidth_calc.{h,cpp} — bandwidth math (KiB→GiB/s, overflow clamping)
  • monitor/arg_parser.{h,cpp}parseMonitorArgs() (errors via struct, no exit(1))
  • example/bw_stats.{h,cpp}computeBandwidthStats()
  • example/arg_parser.{h,cpp}parseBwTestArgs() (errors via struct, no exit(1))

52 tests in test/ covering bandwidth math, both arg parsers, and stats aggregation.

Code fixes

  • -b -1 size_t wraparound: parseCommandLine used std::atoisize_t, so -1 became SIZE_MAX and bypassed the unsigned <= 0 check, then attempted an absurd cudaMalloc. Switched to std::strtol with full validation (non-numeric, ERANGE, sign); negatives now rejected. Includes a regression test.
  • GB→GiB naming: txGBps/rxGBps/totalTxGBps/avgGbps/minGbps/maxGbps held GiB/s values but were named "GB". Renamed to txGiBps/avgGiBps etc. (matching the existing txGiBps local var); example print labels fixed GB/sGiB/s (monitor prints were already correct).

Style & docs

  • Applied clang-format (Google style, 4-space, 80-col, clang-format 14) to all sources.
  • README: fixed monitor usage examples — single-dash long flags (-continuous/-interval/-verbose) didn't work with the hand-rolled parser (exact-string match), changed to --continuous etc.; updated project structure tree; added a Testing section documenting make test/format/check-format and CI.

Verification

  • make check-format → clean
  • make → both GPU binaries build with zero -Wall -Wextra warnings
  • make test → 52/52 pass
  • build/nvlink_bw_test -b -1 → prints "Error: buffer size must be positive", exits 1 (previously attempted cudaMalloc(SIZE_MAX * 1MB))

Notes

  • The GPU binaries (nvlink_monitor, nvlink_bw_test) are not built in CI — they require a CUDA toolkit + driver. This is documented in CODEBUDDY.md and the README.
  • Out of scope: GPU memory prints "GB" (also GiB, but memory capacity not bandwidth); std::localtime thread-safety in formatGPUResult.

Multhree added 6 commits July 10, 2026 02:38
The Makefile hardcoded cuda-12.9 paths, breaking builds on systems
with other CUDA versions, and the monitor rule lacked the NVML
include path (nvml.h lives under the CUDA include dir), causing
"nvml.h: No such file or directory". Use the standard /usr/local/cuda
symlink for both include and lib paths, and add $(CUDA_INCLUDE) to
the monitor compile rule.

Signed-off-by: staryxchen <staryxchen@tencent.com>
Extract pure-logic functions from both binaries into separate translation
units so they can be tested without a GPU:

- monitor/bandwidth_calc.{h,cpp}: calculateBandwidth() moved verbatim
  from NvLinkMonitor::calculateBandwidth (KiB->GiB/s conversion,
  counter-overflow clamping, per-link + per-GPU totals).
- monitor/arg_parser.{h,cpp}: parseMonitorArgs() extracted from main()
  hand-rolled parser; errors now reported via struct fields instead of
  exit(), enabling testability.
- example/bw_stats.{h,cpp}: computeBandwidthStats() extracted from
  testCopyPerformance() (avg/min/max bandwidth + latency math).

Add 34 tests (build/run without a GPU; test binary links only against
the extracted .cpp files + gtest, no NVML/CUDA library symbols):
- test_bandwidth_calc: positive/zero/overflow deltas, multi-link
  aggregation, mismatched snapshot sizes, multi-GPU totals.
- test_arg_parser: defaults, all flags, invalid values, missing values,
  unknown flags, combined options.
- test_bw_stats: known values, single iteration, empty input, all-equal
  timings, min/max inversion.

Makefile: add `test` target (not in default `all`); update monitor/
example source lists to include the extracted .cpp files.

All refactors are behavior-preserving; `make` builds clean with
-Wall -Wextra and `make test` passes 34/34.

Signed-off-by: staryxchen <staryxchen@tencent.com>
Mechanical reformatting of the three pre-existing source files
(monitor/nvlink_monitor.{cpp,h}, example/nvlink_bw_test.cpp) to match
the .clang-format Google-based style. The extracted pure-logic files
and tests added earlier were already format-clean.

No logic changes; only whitespace, line wrapping, and brace placement.

Signed-off-by: staryxchen <staryxchen@tencent.com>
Makefile:
- `make format`: apply clang-format -i to all C++ sources/headers.
- `make check-format`: dry-run with --Werror, fails on violations
  (CI gate). Neither target is in the default `all` build.

CI (.github/workflows/ci.yml), two jobs on ubuntu-22.04:
- format-check: installs clang-format, runs `make check-format`.
- test: installs libnvidia-ml-dev + libgtest-dev, runs `make test`.

The test job needs no GPU: <nvml.h> comes from libnvidia-ml-dev
(/usr/include), gtest ships prebuilt .a on 22.04, and the test binary
links no NVML/CUDA library symbols. $(CUDA_INCLUDE) points to a
nonexistent path in CI; GCC silently ignores nonexistent -I dirs.

The monitor/example GPU binaries are not built in CI (need CUDA
toolkit + driver); CODEBUDDY.md documents this limitation.

Signed-off-by: staryxchen <staryxchen@tencent.com>
Two deferred issues from prior plans:

1. example/nvlink_bw_test.cpp parseCommandLine() called exit(1) on bad
   input (untestable) and `-b -1` wrapped size_t to SIZE_MAX because
   std::atoi("-1") assigned to size_t bypassed the <= 0 check (unsigned).
   Extracted to example/arg_parser.{h,cpp} as parseBwTestArgs(), mirroring
   monitor/arg_parser: errors reported via TestConfig.ok/errorMessage
   (no exit). Parsing switched to std::strtol with full validation
   (non-numeric, ERANGE, sign) so -b -1 is now correctly rejected.
   Added 18 tests in test/test_bw_test_args.cpp including a -b -1
   regression test.

2. txGBps/rxGBps/totalTxGBps/totalRxGBps field names and the example's
   "GB/s" print labels were GiB/s mislabeled as GB. Renamed to
   txGiBps/rxGiBps/totalTxGiBps/totalRxGiBps (matching the existing
   txGiBps local var in bandwidth_calc.cpp), and avgGbps/minGbps/maxGbps
   -> avgGiBps/minGiBps/maxGiBps. Example print labels fixed GB/s->GiB/s.
   Monitor prints already said GiB/s; only field names changed there.
   Removed obsolete "legacy naming" comments.

Makefile: add example/arg_parser.{cpp,h} to example + test build.

make check-format clean; make builds with zero -Wall -Wextra warnings;
make test passes 52/52 (34 existing + 18 new).

Signed-off-by: staryxchen <staryxchen@tencent.com>
- Fix monitor usage examples: single-dash long flags (-continuous,
  -interval, -verbose) did not work with the hand-rolled parser, which
  matches exact strings "-c"/"--continuous" etc. Changed to --continuous,
  --interval, --verbose.
- Update Project Structure tree to list the extracted pure-logic modules
  (bandwidth_calc, arg_parser, bw_stats), the test/ directory, CI
  workflow, and .clang-format.
- Add a Testing section documenting `make test` / `make format` /
  `make check-format`, the no-GPU test binary strategy, and the CI
  configuration.

Signed-off-by: staryxchen <staryxchen@tencent.com>
@staryxchen
staryxchen force-pushed the add-tests-ci-and-fixes branch from 42add31 to 5731b20 Compare July 10, 2026 04:02
@staryxchen
staryxchen merged commit d3539a7 into main Jul 10, 2026
2 checks passed
@staryxchen
staryxchen deleted the add-tests-ci-and-fixes branch July 10, 2026 04:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants