Skip to content

Conversation

@jhendersonHDF
Copy link
Collaborator

@jhendersonHDF jhendersonHDF commented Dec 15, 2025

Fixed an issue that prevented use of a data sieve buffer for I/O on dataset chunks when those chunks couldn't be cached by the library. This issue could result in worst-case behavior of I/O on a single data element at a time when chunks are non-contiguous with respect to memory layout.

Added a test to attempt to catch performance regressions in I/O on dataset chunks that are non-contiguous with respect to memory layout

Updated the External File List logic to set the data sieve buffer size to the smaller of the dataset size and the size set in the FAPL, similar to the logic elsewhere in the library


Important

Re-enable data sieve buffer for non-cached dataset chunks to improve I/O performance and add a test for performance regressions.

  • Behavior:
    • Re-enable data sieve buffer for I/O on non-cached dataset chunks in H5D__chunk_read() and H5D__chunk_write() in H5Dchunk.c.
    • Update H5D__efl_construct() in H5Defl.c to set sieve buffer size to the smaller of dataset size and FAPL size.
    • Add test chunk_non_contig_mem_io in io_perf.c to catch performance regressions for non-contiguous memory layout chunks.
  • Misc:
    • Update CHANGELOG.md to document the performance fix.
    • Add io_perf to H5_EXPRESS_TESTS in CMakeLists.txt.

This description was created by Ellipsis for cb23842. You can customize this summary. It will automatically update as commits are pushed.

@jhendersonHDF jhendersonHDF added Component - C Library Core C library issues (usually in the src directory) Component - Documentation Doxygen, markdown, etc. labels Dec 15, 2025
@jhendersonHDF jhendersonHDF added the Component - Testing Code in test or testpar directories, GitHub workflows label Dec 15, 2025
@github-project-automation github-project-automation bot moved this to To be triaged in HDF5 - TRIAGE & TRACK Dec 15, 2025
@jhendersonHDF
Copy link
Collaborator Author

jhendersonHDF commented Dec 15, 2025

Related writeup:
HDF5_chunked_dataset_IO_performance_issue.pdf

Note that this is a rather quick fix for the issue and a bit of refactoring in the chunked I/O code would be better in the long run.

src/H5Dchunk.c Outdated
*/
dset_info->dset->shared->cache.contig.sieve_buf_size = H5F_SIEVE_BUF_SIZE(dset_info->dset->oloc.file);
dset_info->dset->shared->cache.contig.sieve_loc = HADDR_UNDEF;
dset_info->dset->shared->cache.contig.sieve_size = 0;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These lines are to force re-reads into the sieve buffer on each I/O to account for cases like changing the extent of a dataset between writes and reads

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the sieve buffer isn't persistent for chunked datasets?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we free the sieve buffer after I/O since the data in it is useless?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sieve buffer is currently freed when the dataset is closed, but we could free it after I/O if you think that's better; it just seemed more efficient to keep it around. Setting sieve_loc to HADDR_UNDEF and sieve_size to 0 is just to make sure that the library doesn't read stale data from the sieve buffer in the case where the dataset extent changes. Note the sieve_size here is just the value tracking how much data is currently in the buffer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we don't need the data in the buffer keeping it around is effectively treating it like a buffer on the free list. The sieve buffer is already integrated with the free list however, so I think we should just free it after I/O (it will be held open by the H5FL code if appropriate).

src/H5Defl.c Outdated
/* Get the sieve buffer size for this dataset - the smaller of the dataset size and
* the sieve buffer size from the FAPL is used
*/
dset->shared->cache.contig.sieve_buf_size =
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the EFL code here to set the sieve buffer size to the smaller of the dataset size and the FAPL-specified size. This just matches the logic elsewhere in the library and what's currently documented for H5Pset_sieve_buf_size():

Internally, the library checks the storage sizes of the datasets in
the file. It picks the smaller one between the size from the file
access property and the size of the dataset to allocate the sieve
buffer for the dataset in order to save memory usage.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a sieve buffer is not used, the test in this file is designed to run a long time to try and cause a timeout in CMake for TestExpress of 0, but run very quickly for a TestExpress of 3. We currently do testing with a TestExpress of 0 for every PR, but those tests should probably be moved to a scheduled run as originally intended since tests like this can be problematic for testing at that level for every PR.

mattjala
mattjala previously approved these changes Dec 17, 2025
Fixed an issue that prevented use of a data sieve buffer for I/O on dataset
chunks when those chunks couldn't be cached by the library. This issue
could result in worst-case behavior of I/O on a single data element at a
time when chunks are non-contiguous with respect to memory layout.

Added a test to attempt to catch performance regressions in I/O on dataset
chunks that are non-contiguous with respect to memory layout

Updated the External File List logic to set the data sieve buffer size to
the smaller of the dataset size and the size set in the FAPL, similar to
the logic elsewhere in the library
mattjala
mattjala previously approved these changes Dec 23, 2025
lrknox
lrknox previously approved these changes Jan 16, 2026
@fortnern
Copy link
Member

I would consider this a new feature, not a fix

@fortnern
Copy link
Member

Has data sieving ever been used in this case before? The AI seems to think so but I think it's wrong.

Copy link
Member

@fortnern fortnern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marking "request changes", really just requesting discussion/responses to my comments, then we'll decide if changes are needed

@github-project-automation github-project-automation bot moved this from To be triaged to In progress in HDF5 - TRIAGE & TRACK Jan 16, 2026
@jhendersonHDF
Copy link
Collaborator Author

I would consider this a new feature, not a fix

I can see that, but it was very clearly a bug due to oversight in the way that the chunking code was written which led to drastic performance problems.

Has data sieving ever been used in this case before?

I haven't gone through the history much, but randomly picking 1.10.3 as a test branch shows the same problem.

@ajelenak ajelenak added this to the HDF5 2.1.0 milestone Jan 16, 2026
@jhendersonHDF jhendersonHDF dismissed stale reviews from lrknox and mattjala via 70943da January 16, 2026 20:38
H5FL_EXTERN(H5S_sel_iter_t);

/* Declare the external PQ free list for the sieve buffer information */
H5FL_BLK_EXTERN(sieve_buf);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the sieve buffer being managed by H5Dchunk.c as well, it needs a reference to the free list. This is a bit messy as the sieve buffer is still almost completely controlled by H5Dcontig.c, but refactoring that seems outside the scope of this PR.


done:
/* Free dataset sieve buffer and reset cached fields */
if (dset_info->dset->shared->cache.sieve.sieve_buf) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the resetting of fields in these sections is mostly redundant with the same above, I wanted to keep both so the context (comment) isn't lost in potential future refactoring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Component - C Library Core C library issues (usually in the src directory) Component - Documentation Doxygen, markdown, etc. Component - Testing Code in test or testpar directories, GitHub workflows

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

6 participants