Skip to content

perf(read): build full class names by string concatenation - #920

Merged
ehennestad merged 1 commit into
mainfrom
build-class-name-by-concatenation
Oct 6, 2026
Merged

ehennestad merged 1 commit into
mainfrom
build-class-name-by-concatenation

Conversation

@ehennestad

@ehennestad ehennestad commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

Speeds up nwbRead by building the class name of each typed object with string concatenation instead of compose: a 500-sweep file reads in 9.69 s instead of 11.92 s.

Problem — nwbRead builds the MATLAB class name of every typed group and dataset it reads, for example types.core.CurrentClampSeries from the namespace core and the type CurrentClampSeries. Building each name took about 1.9 ms, almost all of it in the compose call that joins the parts. A patch-clamp file with 500 sweeps has about 2,000 typed objects, so building class names alone adds several seconds to the read. On the DANDI:000541 file from #567, it was about 13% of the read time.

Solution — The parts are joined by string concatenation, which takes about 0.004 ms and gives the same names. Reading the 500-sweep file takes 9.69 s instead of 11.92 s.

Related: #567, #914, #915 and #919, which remove other per-object costs when reading.

What changed

  • nwbRead spends almost no time building class names. Reading a file with many typed objects is about 12–19% faster, depending on the file.
  • Class names are unchanged, including for vector and empty inputs.
Implementation notes

matnwb.common.composeFullClassName now returns "types." + namespaceName + "." + neurodataType instead of compose("types.%s.%s", namespaceName, neurodataType). The two give identical results for scalar, column, mixed scalar and column, and empty inputs. The function had no tests; ComposeFullClassNameTest covers these cases and the existing name corrections.

Examples

Reading a patch-clamp file with 500 sweeps

The file has one CurrentClampSeries per sweep; the code that creates it is in #914. This reads the file and reports the fastest of three reads. The file and the code are the same before and after.

filename = "sweeps.nwb";

nwbRead(filename, "ignorecache"); % warm up
times = zeros(1, 3);
for k = 1:3
    t = tic;
    nwb = nwbRead(filename, "ignorecache");
    times(k) = toc(t);
end
fprintf("sweeps read: %d\n", nwb.acquisition.Count);
fprintf("read time: %.2f s\n", min(times));

Before — All 500 sweeps are read in almost 12 seconds.

sweeps read: 500
read time: 11.92 s

After — The same sweeps are read in about 2 seconds less.

sweeps read: 500
read time: 9.69 s

How to test

Run the example above on main and on this branch. The class names are covered by:

runtests("tests.unit.common.ComposeFullClassNameTest")

Checklist

  • Have you ensured the PR description clearly describes the problem and solutions?
  • Have you checked to ensure that there aren't other open or previously closed Pull Requests for the same change?
  • If this PR fixes an issue, is the first line of the PR description fix #XX where XX is the issue number?

🤖 Generated with Claude Code

matnwb.common.composeFullClassName runs once for every typed object
read from a file, through io.getNeurodataTypeInfo. Building the name
with compose took about 1.8 ms per call, almost all of the function's
time. Concatenating the strings takes about 0.004 ms and gives the
same result for scalar, vector and empty inputs.

Reading a file with 500 sweeps takes 8.5 s instead of 9.7 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ehennestad
ehennestad requested a review from bendichter October 1, 2026 19:32
@codecov

codecov Bot commented Oct 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.30%. Comparing base (1565936) to head (e1c45a4).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #920      +/-   ##
==========================================
+ Coverage   95.29%   95.30%   +0.01%     
==========================================
  Files         239      239              
  Lines        8795     8795              
==========================================
+ Hits         8381     8382       +1     
+ Misses        414      413       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ehennestad
ehennestad enabled auto-merge October 2, 2026 08:01
@ehennestad
ehennestad added this pull request to the merge queue Oct 6, 2026
Merged via the queue into main with commit e960ac3 Oct 6, 2026
20 checks passed
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