Saving a multi-segment recording fails when only some segments have a t_start

Đang mở Phù hợp với người mới
#4,914 1 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
84/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
numpy, python
Lĩnh vực
backend, data

Hướng nghiên cứu

Bắt đầu với ba constructor được nêu trong issue: NumpyRecording và SharedMemoryRecording trong src/spikeinterface/core/numpyextractors.py, và BinaryRecordingExtractor trong src/spikeinterface/core/binaryrecordingextractor.py. Đọc cách từng constructor xử lý get_segment_t_starts, sau đó chạy bước tái hiện lỗi và các bài kiểm thử recording và binary extractor được nêu tên. Công việc hoàn tất khi các bản lưu nhị phân và trong bộ nhớ giữ nguyên các thời điểm bắt đầu hỗn hợp và traces, đồng thời không để lại shared memory chưa được giải phóng.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

core

get_segment_t_starts returns a mixed list such as [None, 100.0] when only some segments have a start time. Three constructors then call float() on every entry. This happens with append_recordings([rec_without_t_start, rec_with_t_start]), and more generally when shift_times has been applied to only some segments.

Reproduction

main at 9ef464e66, Linux (WSL Ubuntu 24.04), Python 3.12.3, numpy 2.5.4, zarr 3.4.2:

import spikeinterface.core as sc

a = sc.generate_recording(num_channels=2, sampling_frequency=1000.0, durations=[3.0], seed=0)
b = sc.generate_recording(num_channels=2, sampling_frequency=1000.0, durations=[2.0], seed=1)
b.shift_times(100.0)
rec = sc.append_recordings([a, b])
print(rec.get_segment_t_starts(), [rec.get_start_time(i) for i in range(2)])

for kwargs in [
    dict(format="binary", folder="rec_binary"),
    dict(format="memory", shared_memory=False),
    dict(format="memory", shared_memory=True),
    dict(format="zarr", folder="rec.zarr"),
]:
    try:
        saved = rec.save(**kwargs)
        print(kwargs["format"], "OK", [saved.get_start_time(i) for i in range(2)])
    except TypeError as ex:
        print(kwargs["format"], f"TypeError: {ex}")
[None, 100.0] [0.0, 100.0]
binary TypeError: float() argument must be a string or a real number, not 'NoneType'
memory TypeError: float() argument must be a string or a real number, not 'NoneType'
memory TypeError: float() argument must be a string or a real number, not 'NoneType'
zarr OK [0.0, array(100.)]

Three details make this worse:

  • Binary: the exception comes after all traces are written. In the example, rec_binary contains traces_cached_seg0.raw and traces_cached_seg1.raw, but neither binary.json nor si_folder.json. For a long recording, this means that hours of writing end in a folder that cannot be loaded.
  • Shared memory: the exception comes before self.main_shm_owner is set, so __del__ raises AttributeError: 'SharedMemoryRecording' object has no attribute 'main_shm_owner', and the segments are not unlinked. The script ends with resource_tracker: There appear to be 4 leaked shared_memory objects to clean up at shutdown.
  • Zarr: saving works, but get_start_time(1) returns a 0-d array(100.) instead of a float.
Cause

get_segment_t_starts only returns None when all segments have no start time. The conversion is in NumpyRecording, SharedMemoryRecording and BinaryRecordingExtractor. In SharedMemoryRecording, main_shm_owner is set after this line, and __del__ reads it.

Possible fix

In the three constructors, keep None:

t_starts = [None if t_start is None else float(t_start) for t_start in t_starts]

With this, the binary and both memory saves work, with start times [0.0, 100.0] and identical traces, and the script no longer reports leaked segments. test_basesorting.py, test_baserecording.py, test_binaryfolder.py, test_binaryrecordingextractor.py and test_numpy_extractors.py still pass (33 tests).

Two separate points would remain: setting main_shm_owner before anything that can fail, so that __del__ is safe after another error, and the 0-d array from zarr. I have not changed them.

I found no report of this case. Nearby: #2515 and #3120 (t_starts lost by save_to_memory) and #3940 (shift_times when t_start is None). I can open a PR with this change and a round-trip test.

Ngôn ngữ chính
Python
Star
870
Fork
284
Merge trung bình
3 ngày 1 giờ
Pull request đã merge (30 ngày)
41

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của SpikeInterface/spikeinterface

Tất cả issue của SpikeInterface/spikeinterface

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.