You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Reuse a fit's CSV metadata on subsequent reads #1314
I noticed then when reviewing #1312 and I had Claude run some tests and help generate this report.
read_csv_metadata() greps every chain file for its comment lines, so the cost of reading the metadata grows with the number of draws even though the metadata is a few hundred lines. Every read_cmdstan_csv() call pays it per file: every $draws() on a variable not yet read, every $summary() and $sampler_diagnostics() on a fresh fit, and as_cmdstan_fit().
Measured on macOS with CmdStan 2.40.0, 4 chains, 1000 draws, medians of 5:
per chain file
4 metadata scans
one-variable read_cmdstan_csv() call
10 parameters, 0.16 MB
0.12 s
0.15 s
1000 parameters, 11 MB
0.44 s
0.91 s
So the scan is most of a read on a small fit and about half on a large one, roughly 10 ms per MB of CSV on each read.
The fix is for a fit to reuse its own metadata: after the first read the fit holds the merged metadata and its files don't change, so later reads pass it back to the reader and skip the scan. That leaves one scan per fit, on the first read.
Possible design: the parse-and-merge loop in read_cmdstan_csv() becomes merge_csv_metadata(files), returning the merged metadata with the per-chain inverse metric and step size lists. The body of read_cmdstan_csv() moves to an internal function with a csv_metadata argument that skips the merge when given one and returns it, and the exported function stays a wrapper with the same arguments and return value. CmdStanMCMC and CmdStanGQ (the two classes that read more than once) store the merged metadata on the first read and pass it on later ones. The processed metadata the fit already stores can't be handed back directly: the reader selects columns by the raw CSV names (theta.1) and the fit's copy has the repaired ones (theta[1]).
A reader that takes the head until the first data...
I thought a little about this when writing #1312, and the main issue I had with a custom scan was that we would need to roll our own reader, right? I'm not super familiar with grep so maybe it's possible to give it bounds which would be nice, but writing our own reader almost seems worse than eating the performance?
But if it's much easier/safer than I'm thinking to write our own reader, or there's a nice way to shop it out to a dep I think that reading just the metadata would be very good to have.
Good point, you're right! I still don't think we should add the cache, but I don't think we should do our own reader either.
I think we can just stop re-parsing at all for a fit we already read. After the first read the fit has the merged metadata and its files won't change, so later reads ($draws() on a new variable, $summary(), $sampler_diagnostics()) can just pass the info back to read_cmdstan_csv() and skip the scan. Right? I think that should work, but I'll double check. Then we just have one scan per fit on the first read, which is fine.
changed the title [-]Don't scan whole file when reading the metadata of a CSV file[/-][+]Reuse a fit's CSV metadata on subsequent reads[/+]on Oct 7, 2026
I updated the issue body with the new idea, which isn't quite as simple as just passing it back to read_cmdstan_csv(), but I think is still relatively simple.
It might not be that bad to write a little reader, so maybe doing a little experiment is worthwhile to see the performance gains? Would really depend on how complex the reader would have to be and how much runtime or memory is saved.
Activity
VisruthSK commentedon Oct 7, 2026
I thought a little about this when writing #1312, and the main issue I had with a custom scan was that we would need to roll our own reader, right? I'm not super familiar with
grepso maybe it's possible to give it bounds which would be nice, but writing our own reader almost seems worse than eating the performance?But if it's much easier/safer than I'm thinking to write our own reader, or there's a nice way to shop it out to a dep I think that reading just the metadata would be very good to have.
jgabry commentedon Oct 7, 2026
Good point, you're right! I still don't think we should add the cache, but I don't think we should do our own reader either.
I think we can just stop re-parsing at all for a fit we already read. After the first read the fit has the merged metadata and its files won't change, so later reads (
$draws()on a new variable,$summary(),$sampler_diagnostics()) can just pass the info back toread_cmdstan_csv()and skip the scan. Right? I think that should work, but I'll double check. Then we just have one scan per fit on the first read, which is fine.[-]Don't scan whole file when reading the metadata of a CSV file[/-][+]Reuse a fit's CSV metadata on subsequent reads[/+]jgabry commentedon Oct 7, 2026
I updated the issue body with the new idea, which isn't quite as simple as just passing it back to
read_cmdstan_csv(), but I think is still relatively simple.VisruthSK commentedon Oct 7, 2026
Yeah the proposed solutions seems good.
It might not be that bad to write a little reader, so maybe doing a little experiment is worthwhile to see the performance gains? Would really depend on how complex the reader would have to be and how much runtime or memory is saved.