Sample report: Earthworm
A Tezcatl baseline of Earthworm, the open-source
(MIT) seismic processing system, written mostly in C. Generated 2026-09-25.
| Earthworm | gitlab.com/seismic-software/earthworm, commit 6e57b315417ff22e9b255c3bb0d5e47c9086871a (2026-09-25) |
| Tezcatl | commit 27298a4, libclang 22.1.8 |
| Build | Ubuntu 24.04.5, gcc and gfortran 13.3.0, make unix under bear 3.1.3 |
| Units | 929 C and C++ translation units parsed, 0 with errors; 120 Fortran entries skipped |
| Run | 3.5 s at 16 threads, 23.7 s on one; 782 MB and 536 MB peak (Release build, AMD Ryzen 7 7840HS; re-timed 2026-09-26 with commit 3a39a64, whose output is byte-identical to this report’s) |
Files here: report.md (the report), modules.csv (every metric per
module), the include-graph module tables, and modules.txt, the module map. The
full output (13 MB of JSON, per-function and per-declaration CSV) is not committed; it is
regenerated by the commands below.
Reproduce
git clone https://gitlab.com/seismic-software/earthworm.git && cd earthworm
git checkout 6e57b315417ff22e9b255c3bb0d5e47c9086871a
export EW_INSTALL_HOME=$(dirname $PWD) EW_INSTALL_VERSION=earthworm EW_INSTALL_BITS=64
source environment/ew_linux.bash
(cd src && bear --output ../compile_commands.json -- make unix) # needs libtirpc-dev, gfortran
tezcatl report -p . --root . --out report \
--modules /path/to/tezcatl/docs/sample-report/earthworm/modules.txt
Both packages matter, and neither failure is loud. Without libtirpc-dev, libuw fails and the
database holds 247 entries. Without gfortran, hyp2000 fails; Earthworm’s makefiles stop a
category at its first failing module and the top level stops at the first failing category, so
system_control is never built, and make -k does not change that. That run gave 915 entries
and looked complete. The run above has 1,049 entries and make exits 0.
Reading it
- 57% of the code is not Earthworm’s. Bundled libraries are 540,929 of the 951,565 code
lines and 6,324 of the 11,029 functions: SQLite’s amalgamation alone is 130,545 lines, the
MySQL connector insidemole192,971, IRIS’s libslink with Mbed TLS 125,709. Each is its own
third-party/...module, identified by its own copyright notices and licence files (see
modules.txt). Earthworm’s own code is 410,636 code lines in 4,705 functions. - 1,326 of 2,910 source files are not parsed, and the report says so before any figure. They
are code for Windows and Solaris, and modules Earthworm’s Linux build leaves out (mole, and
with it all 509 files of the MySQL connector). They count in lines of code and nothing else;
the summary shows each module’s files with how many were parsed. - 62 C files are compiled more than once with different
-Dflags (ringdup.cbecomes
three programs). Each is measured as its first compile command. - No include cycles, at file or module level.
How far to trust the complexity figures
lizard 1.24.0, an independent tool, was run on the same files:
| Comparison | Functions matched | Same complexity |
|---|---|---|
| lizard on the raw source, matched by file and line | 8,165 | 6,862 (84.0%) |
lizard on each unit as compiled (gcc -E -fdirectives-only with the unit’s flags), by file and name |
9,935 | 9,348 (94.1%) |
| the same, outside SQLite’s amalgamation | 7,962 | 7,885 (99.0%) |
lizard has no preprocessor: on raw source it counts both sides of every #if, and Earthworm’s
C is full of #ifdef _WINNT and _SOLARIS. Measured in the same configuration, 510 of the 587
remaining differences are in sqlite3.c, for two reasons checked in its source:
- Macros that compile to nothing.
exprCodeBetweenhas oneifand eight
testcase(a && b && c)lines;testcase()is empty outside SQLite’s coverage builds, so the
compiled function has complexity 2 (Tezcatl), while lizard counts the sixteen&&as text
(18).assert()is the same under theNDEBUGSQLite defines. - Different
#ifbranches: SQLite tests for__clang__, and the parser is clang
(sqlite3MulInt64: 11 against 1; see docs/metrics.md).
Of the other 77, 10 are in files compiled several ways, where the oracle compares every
configuration against Tezcatl’s one; 67 are in files compiled once, mostly off by one, in both
directions, across about 40 files. Two were checked by hand: in grf2ew/ustime.c lizard counts
the && inside ASSERT(doy >= 1 && doy <= 366), a disabled assertion (Tezcatl is right as
compiled); in libsrc/unix/transport.c, tport_copyto has 15 decisions in its compiled branch
(11 if, 2 while, 1 for, 1 &&), so complexity 16, Tezcatl’s figure, where lizard gives 15.
The remaining 65 have not been looked at one by one.
Checking this comparison found two defects in Tezcatl before this report was published: which
configuration of a file compiled twice survived depended on the standard library’s unstable
sort, and a build directory equal to the root (as bear makes) excluded the whole project. Both
are fixed and tested.