REAL WORKLOAD · 6 NOVEMBER 2026 · LOCAL ANALYSIS
134,737 unique lines.
85 units completed.
Study context
- Problem addressed
- How much of a real C/C++ corpus can an isolated analysis workflow cover?
- Contribution relative to existing methods
- The benchmark reports coverage for both established analyzers on the same corpus and records the execution conditions.
- Potential commercial use
- Assess the scope of an offline firmware review before a pilot.
ESAE · C/C++
Experiment conclusions
On the Mini M1, Cppcheck and clang-tidy completed all 85 selected translation units, covering 134,737 unique lines, in 11 minutes 30 seconds. With the initial profile, clang-tidy completed 33 within its time budget.
Study limits. The result applies to the tested workload and configuration. Time limits and configuration also changed between profiles, so the timings do not measure a speedup. The scan provides no software certification.
Cppcheck 2.22.0 CLI/core, including its selected vendored dependencies. GUI, tests, add-ons and tools excluded. A serial, checkpointed analysis of the 85 translation units from an actual successful Mac arm64 C++11 build.
Largest workload qualified so far in this experiment. This is not a universal maximum, a single standard dashboard job, or a claim of whole-program verification.
What was actually run
ESAE orchestrated Cppcheck 2.22.0 and clang-tidy 23.1.4 locally on a Mac mini M1, 16 GiB, macOS 27, Python 3.12. 186 unique files, 5,315,690 bytes; 85 source translation units and 101 project headers. Shared headers count once. System SDK headers are not included in the line count. All selected source hashes match the pinned upstream archive.
One unit and one native analyzer process at a time; 120 seconds per process, 300 seconds native budget per unit. A selected Mac arm64 C++11 configuration, with verified host predefines and explicitly absent foreign-platform macros. Native checks still run with bounded read-only snapshots, no network and mandatory macOS sandbox. No repository script or compilation command was executed during the benchmark. One selected Cppcheck configuration per compilation database entry; other platform configurations are not covered.
Measurement and repeatability
The full queue took 689.715 seconds, excluding source download, tool installation and unit preparation. Analyzer peak RSS was 565,968,896 bytes; controller peak RSS was 149,798,912 bytes. These are separate process high-water marks, not simultaneous total memory consumption.
85 / 85 units completed, 170 successful analyzer invocations, zero detected execution/configuration errors; original selected sources unchanged. Completion does not prove every code path was analyzed. The full run used the local hardening candidate recorded as 0.1.0. The two slowest units were repeated on final 0.1.1 code, with identical semantic diagnostic signatures. This is not a second full 85-unit run. The public reproduction command was separately stopped after one unit and resumed on the second without replay. 53 regression tests passed, zero failures or skips.
The initial limit remains visible
The initial single-job baseline used 30 seconds per process and a 300-second native budget: it stopped partially after 305.215 seconds, with 33 of 85 clang-tidy units completed and a Cppcheck timeout. The later qualification also corrected target macros and configuration selection; these figures are not a controlled speedup comparison. Godot's million-line repository was previously inventoried but not completely analyzed. No completed million-line result is claimed.
Reproduce locally
Download the ESAE 0.1.1 source, follow its explicit macOS setup, then run:
.venv/bin/python -m benchmarks.reproduce_cppcheck --output .local/cppcheck-benchmarkOptionally add --max-new-units 5 and rerun the same command to resume. The example verifies the archive and source hashes and rejects changed engine/profile/toolchain checkpoints. It downloads public GPL-3.0-or-later source locally; no third-party source is included in the ESAE source distribution.
Recipe and hash manifest · Official upstream release · Machine-readable results
Explicit boundaries
Source limits remain 1,000 files / 50 MB and 2 MB per file per scan; default single-job native budget remains 300 seconds. The separate example orchestrates bounded scans. No whole-program cross-unit property, WCET, race-freedom, formal correctness or safety certification is verified. Native diagnostics require review and are not a count of confirmed bugs. No AI, cloud or user-code upload was used. Windows/Linux qualification is not implied.
All 85 translation units
| # | Translation unit | Analyzers completed | Unit wall time | Errors |
|---|---|---|---|---|
| 01 | externals/simplecpp/simplecpp.cpp | 2 / 2 | 19.718 s | 0 |
| 02 | externals/tinyxml2/tinyxml2.cpp | 2 / 2 | 15.008 s | 0 |
| 03 | lib/valueflow.cpp | 2 / 2 | 70.982 s | 0 |
| 04 | lib/tokenize.cpp | 2 / 2 | 32.132 s | 0 |
| 05 | lib/symboldatabase.cpp | 2 / 2 | 56.417 s | 0 |
| 06 | lib/addoninfo.cpp | 2 / 2 | 2.442 s | 0 |
| 07 | lib/analyzerinfo.cpp | 2 / 2 | 5.660 s | 0 |
| 08 | lib/astutils.cpp | 2 / 2 | 37.368 s | 0 |
| 09 | lib/check64bit.cpp | 2 / 2 | 2.577 s | 0 |
| 10 | lib/checkassert.cpp | 2 / 2 | 2.678 s | 0 |
| 11 | lib/checkautovariables.cpp | 2 / 2 | 4.604 s | 0 |
| 12 | lib/checkbool.cpp | 2 / 2 | 2.726 s | 0 |
| 13 | lib/checkbufferoverrun.cpp | 2 / 2 | 3.925 s | 0 |
| 14 | lib/checkclass.cpp | 2 / 2 | 19.982 s | 0 |
| 15 | lib/checkcondition.cpp | 2 / 2 | 13.274 s | 0 |
| 16 | lib/checkers.cpp | 2 / 2 | 0.912 s | 0 |
| 17 | lib/checkersidmapping.cpp | 2 / 2 | 0.680 s | 0 |
| 18 | lib/checkersreport.cpp | 2 / 2 | 3.675 s | 0 |
| 19 | lib/checkexceptionsafety.cpp | 2 / 2 | 2.764 s | 0 |
| 20 | lib/checkfunctions.cpp | 2 / 2 | 4.971 s | 0 |
| 21 | lib/checkimpl.cpp | 2 / 2 | 1.225 s | 0 |
| 22 | lib/checkinternal.cpp | 2 / 2 | 0.385 s | 0 |
| 23 | lib/checkio.cpp | 2 / 2 | 13.856 s | 0 |
| 24 | lib/checkleakautovar.cpp | 2 / 2 | 6.905 s | 0 |
| 25 | lib/checkmemoryleak.cpp | 2 / 2 | 8.005 s | 0 |
| 26 | lib/checknullpointer.cpp | 2 / 2 | 4.673 s | 0 |
| 27 | lib/checkother.cpp | 2 / 2 | 18.483 s | 0 |
| 28 | lib/checkpostfixoperator.cpp | 2 / 2 | 2.552 s | 0 |
| 29 | lib/checks.cpp | 2 / 2 | 2.352 s | 0 |
| 30 | lib/checksizeof.cpp | 2 / 2 | 4.380 s | 0 |
| 31 | lib/checkstl.cpp | 2 / 2 | 17.271 s | 0 |
| 32 | lib/checkstring.cpp | 2 / 2 | 3.442 s | 0 |
| 33 | lib/checktype.cpp | 2 / 2 | 4.847 s | 0 |
| 34 | lib/checkuninitvar.cpp | 2 / 2 | 9.068 s | 0 |
| 35 | lib/checkunusedfunctions.cpp | 2 / 2 | 7.141 s | 0 |
| 36 | lib/checkunusedvar.cpp | 2 / 2 | 8.981 s | 0 |
| 37 | lib/checkvaarg.cpp | 2 / 2 | 2.766 s | 0 |
| 38 | lib/clangimport.cpp | 2 / 2 | 8.089 s | 0 |
| 39 | lib/color.cpp | 2 / 2 | 1.251 s | 0 |
| 40 | lib/cppcheck.cpp | 2 / 2 | 9.028 s | 0 |
| 41 | lib/ctu.cpp | 2 / 2 | 9.629 s | 0 |
| 42 | lib/errorlogger.cpp | 2 / 2 | 8.994 s | 0 |
| 43 | lib/errortypes.cpp | 2 / 2 | 0.793 s | 0 |
| 44 | lib/findtoken.cpp | 2 / 2 | 4.059 s | 0 |
| 45 | lib/forwardanalyzer.cpp | 2 / 2 | 5.273 s | 0 |
| 46 | lib/fwdanalysis.cpp | 2 / 2 | 4.973 s | 0 |
| 47 | lib/importproject.cpp | 2 / 2 | 14.400 s | 0 |
| 48 | lib/infer.cpp | 2 / 2 | 5.301 s | 0 |
| 49 | lib/keywords.cpp | 2 / 2 | 0.797 s | 0 |
| 50 | lib/library.cpp | 2 / 2 | 11.752 s | 0 |
| 51 | lib/mathlib.cpp | 2 / 2 | 4.521 s | 0 |
| 52 | lib/path.cpp | 2 / 2 | 1.593 s | 0 |
| 53 | lib/pathanalysis.cpp | 2 / 2 | 2.933 s | 0 |
| 54 | lib/pathmatch.cpp | 2 / 2 | 2.035 s | 0 |
| 55 | lib/platform.cpp | 2 / 2 | 3.447 s | 0 |
| 56 | lib/preprocessor.cpp | 2 / 2 | 12.072 s | 0 |
| 57 | lib/programmemory.cpp | 2 / 2 | 11.247 s | 0 |
| 58 | lib/regex.cpp | 2 / 2 | 0.329 s | 0 |
| 59 | lib/reverseanalyzer.cpp | 2 / 2 | 2.919 s | 0 |
| 60 | lib/sarifreport.cpp | 2 / 2 | 3.057 s | 0 |
| 61 | lib/settings.cpp | 2 / 2 | 4.842 s | 0 |
| 62 | lib/standards.cpp | 2 / 2 | 0.939 s | 0 |
| 63 | lib/summaries.cpp | 2 / 2 | 4.481 s | 0 |
| 64 | lib/suppressions.cpp | 2 / 2 | 12.784 s | 0 |
| 65 | lib/templatesimplifier.cpp | 2 / 2 | 20.189 s | 0 |
| 66 | lib/timer.cpp | 2 / 2 | 2.391 s | 0 |
| 67 | lib/token.cpp | 2 / 2 | 21.119 s | 0 |
| 68 | lib/tokenlist.cpp | 2 / 2 | 14.374 s | 0 |
| 69 | lib/utils.cpp | 2 / 2 | 1.550 s | 0 |
| 70 | lib/vf_analyzers.cpp | 2 / 2 | 12.006 s | 0 |
| 71 | lib/vf_common.cpp | 2 / 2 | 3.902 s | 0 |
| 72 | lib/vf_settokenvalue.cpp | 2 / 2 | 3.087 s | 0 |
| 73 | lib/vfvalue.cpp | 2 / 2 | 2.527 s | 0 |
| 74 | frontend/frontend.cpp | 2 / 2 | 1.054 s | 0 |
| 75 | cli/cmdlineparser.cpp | 2 / 2 | 17.411 s | 0 |
| 76 | cli/cppcheckexecutor.cpp | 2 / 2 | 4.400 s | 0 |
| 77 | cli/executor.cpp | 2 / 2 | 1.887 s | 0 |
| 78 | cli/filelister.cpp | 2 / 2 | 2.683 s | 0 |
| 79 | cli/main.cpp | 2 / 2 | 0.846 s | 0 |
| 80 | cli/processexecutor.cpp | 2 / 2 | 3.289 s | 0 |
| 81 | cli/sehwrapper.cpp | 2 / 2 | 0.324 s | 0 |
| 82 | cli/signalhandler.cpp | 2 / 2 | 0.858 s | 0 |
| 83 | cli/singleexecutor.cpp | 2 / 2 | 1.045 s | 0 |
| 84 | cli/stacktrace.cpp | 2 / 2 | 0.988 s | 0 |
| 85 | cli/threadexecutor.cpp | 2 / 2 | 3.221 s | 0 |