Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only assign memmap within boundaries for write_binary #2796

Merged
merged 6 commits into from
May 21, 2024
Merged
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 22 additions & 15 deletions src/spikeinterface/core/recording_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,33 +152,40 @@ def _write_binary_chunk(segment_index, start_frame, end_frame, worker_ctx):
cast_unsigned = worker_ctx["cast_unsigned"]
file = worker_ctx["file_dict"][segment_index]

# Open the memmap
# What we need is the file_path
num_channels = recording.get_num_channels()
num_frames = recording.get_num_frames(segment_index=segment_index)
shape = (num_frames, num_channels)
dtype_size_bytes = np.dtype(dtype).itemsize
data_size_bytes = dtype_size_bytes * num_frames * num_channels

# Offset (The offset needs to be multiple of the page size)
# The mmap offset is associated to be as big as possible but still a multiple of the page size
# The array offset takes care of the reminder
mmap_offset, array_offset = divmod(byte_offset, mmap.ALLOCATIONGRANULARITY)
mmmap_length = data_size_bytes + array_offset
memmap_obj = mmap.mmap(file.fileno(), length=mmmap_length, access=mmap.ACCESS_WRITE, offset=mmap_offset)
# Calculate byte offsets for the start and end frames relative to the entire recording
start_byte = byte_offset + start_frame * num_channels * dtype_size_bytes
end_byte = byte_offset + end_frame * num_channels * dtype_size_bytes

array = np.ndarray.__new__(np.ndarray, shape=shape, dtype=dtype, buffer=memmap_obj, order="C", offset=array_offset)
# apply function
# The mmap offset must be a multiple of mmap.ALLOCATIONGRANULARITY
memmap_offset, start_offset = divmod(start_byte, mmap.ALLOCATIONGRANULARITY)
memmap_offset *= mmap.ALLOCATIONGRANULARITY

# This maps in bytes the region of the memmap that corresponds to the chunk
length = (end_byte - start_byte) + start_offset
memmap_obj = mmap.mmap(file.fileno(), length=length, access=mmap.ACCESS_WRITE, offset=memmap_offset)

# To use numpy semantics we use the array interface of the memmap object
num_frames = end_frame - start_frame
shape = (num_frames, num_channels)
memmap_array = np.ndarray(shape=shape, dtype=dtype, buffer=memmap_obj, offset=start_offset)

# Extract the traces and store them in the memmap array
traces = recording.get_traces(
start_frame=start_frame, end_frame=end_frame, segment_index=segment_index, cast_unsigned=cast_unsigned
)

if traces.dtype != dtype:
traces = traces.astype(dtype, copy=False)
array[start_frame:end_frame, :] = traces

# Close the memmap
memmap_array[...] = traces

memmap_obj.flush()

memmap_obj.close()
Copy link
Member

Choose a reason for hiding this comment

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

Do we need this ?
the memmap_ojob is deleted no ?
This is a bit confusing because the file is stil open. Are we sure that this line do not close the underlying file ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I am not sure but the file is not closed, otherwise the tests would not work.



write_binary_recording.__doc__ = write_binary_recording.__doc__.format(_shared_job_kwargs_doc)

Expand Down
Loading