Skip to content

Commit

Permalink
Added a first_timestamp_only method that runs very fast
Browse files Browse the repository at this point in the history
  • Loading branch information
StephenThornquist committed Jul 5, 2024
1 parent 6295b45 commit ac104fb
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 73 deletions.
2 changes: 1 addition & 1 deletion benches/metadata_benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fn criterion_benchmark_frame_metadata(c: &mut Criterion) {
),
&(),
|bench, _| {
bench.iter(|| black_box(corrosiff::SiffReader::scan_timestamps(LONG_SIFF_PATH).unwrap()))
bench.iter(|| black_box(corrosiff::scan_timestamps(&LONG_SIFF_PATH).unwrap()))
},
);

Expand Down
29 changes: 21 additions & 8 deletions benches/opening_files_benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,35 @@ fn criterion_benchmark(c: &mut Criterion) {
// c.bench_function("open a mounted siff file",
// |b| b.iter(|| black_box(open_mount_siff()))
// );
// c.bench_function("open a short siff file",
// |b| b.iter(|| black_box(open_short_siff_test()))
// );
// c.bench_function("open a long siff file", |b| b.iter(|| black_box(open_long_siff_test())));
c.bench_function("open a short siff file",
|b| b.iter(|| black_box(open_short_siff_test()))
);
c.bench_function("open a long siff file", |b| b.iter(|| black_box(open_long_siff_test())));

c.bench_function("Scan first timestamp for short siff",
|b| b.iter(|| black_box(corrosiff::scan_first_timestamp(
&"/Users/stephen/Desktop/Data/imaging/2024-04/2024-04-07/Dh31_LexA_LKir_LGFlamp1/Fly1/BarOnAtTen_1.siff"
).unwrap()))
);

c.bench_function("Scan timestamps for short siff",
|b| b.iter(|| black_box(corrosiff::SiffReader::scan_timestamps(
"/Users/stephen/Desktop/Data/imaging/2024-04/2024-04-07/Dh31_LexA_LKir_LGFlamp1/Fly1/BarOnAtTen_1.siff"
|b| b.iter(|| black_box(corrosiff::scan_timestamps(
&"/Users/stephen/Desktop/Data/imaging/2024-04/2024-04-07/Dh31_LexA_LKir_LGFlamp1/Fly1/BarOnAtTen_1.siff"
).unwrap()))
);

c.bench_function("Scan first timestamp for long siff",
|b| b.iter(|| black_box(corrosiff::scan_first_timestamp(
&"/Users/stephen/Desktop/Data/imaging/2024-04/2024-04-17/21Dhh_GCaFLITS/Fly1/Flashes_1.siff"
).unwrap()))
);

c.bench_function("Scan timestamps for long siff",
|b| b.iter(|| black_box(corrosiff::SiffReader::scan_timestamps(
"/Users/stephen/Desktop/Data/imaging/2024-04/2024-04-17/21Dhh_GCaFLITS/Fly1/Flashes_1.siff"
|b| b.iter(|| black_box(corrosiff::scan_timestamps(
&"/Users/stephen/Desktop/Data/imaging/2024-04/2024-04-17/21Dhh_GCaFLITS/Fly1/Flashes_1.siff"
).unwrap()))
);

}

criterion_group!(benches, criterion_benchmark);
Expand Down
116 changes: 115 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
use std::{
io::Result as IOResult,
io::Error as IOError,
io::Seek,
path::{Path,PathBuf},
fs::File,
collections::HashMap,
};
use binrw::BinRead;

use ndarray::prelude::*;

Expand Down Expand Up @@ -240,10 +242,105 @@ pub fn time_axis_epoch_both(
siffreader.get_epoch_timestamps_both(siffreader.frames_vec().as_slice())
}

/// Finds the first timestamp in the `.siff` file and
/// returns it in nanoseconds since epoch
///
/// ## Arguments
///
/// * `file_path` - The path of the file to scan
///
/// ## Returns
///
/// * `Result<u64, CorrosiffError>` - The timestamp of the first frame
/// in nanoseconds since the Unix epoch (1970-01-01).
///
/// ## See also
///
/// - `scan_timestamps` for the timestamps of the first and last frames
/// (considerably slower)
pub fn scan_first_timestamp<P : AsRef<Path>>(file_path : &P)
-> Result<u64, CorrosiffError> {
let mut file = File::open(file_path)?;

let file_format = tiff::FileFormat::minimal_filetype(&mut file)
.map_err(|_| CorrosiffError::FileFormatError)?;

file.seek(std::io::SeekFrom::Start(file_format.first_ifd_val())).unwrap();

let first_ifd = tiff::BigTiffIFD::read(&mut file)
.map_err(|_| CorrosiffError::FileFormatError)?;

Ok(
metadata::get_epoch_timestamps_laser(
&[&first_ifd],
&mut file
)[0]
)
}

/// Finds the timestamps of the first and last
/// frames of the requested file and returns them
/// as nanoseconds since the Unix epoch (1970-01-01).
/// Uses the system clock stamps of the microscope
/// computer. Almost as slow as just opening
/// the file and querying it yourself though!
///
/// ## Arguments
///
/// * `file_path` - The path of the file to scan
///
/// ## Returns
///
/// * `Result<(u64,u64), CorrosiffError>` - A tuple of two `u64` values
/// representing the timestamps of the first and last frames, respectively.
///
/// ## See also
///
/// - `scan_first_timestamp` for just the timestamp of the first frame,
/// which is considerably faster because it does not need to crawl through
/// every IFD to find the last one.
pub fn scan_timestamps<P: AsRef<Path>>(
file_path : &P,
) -> Result<(u64,u64), CorrosiffError> {
SiffReader::scan_timestamps(file_path)
let mut file = File::open(file_path)?;

let file_format = tiff::FileFormat::minimal_filetype(&mut file)
.map_err(|e| CorrosiffError::FileFormatError)?;

let mut ifd_buff = binrw::io::BufReader::with_capacity(400, &file);
let mut ifds = file_format.get_ifd_iter(&mut ifd_buff);

Ok(
(
metadata::get_epoch_timestamps_laser(
&[&ifds.next().ok_or_else(|| CorrosiffError::FileFormatError)?],
&mut ifds.reader
)[0],

metadata::get_epoch_timestamps_laser(
&[&ifds.last().ok_or_else(||CorrosiffError::FileFormatError)?],
&mut file
)[0]
)
)

// Should I try using the IFDPtrIterator? Doesn't seem to
// actually provide much speedup....

// let mut for_ifd = std::fs::File::open(&filename)?;
// for_ifd.seek(std::io::SeekFrom::Start(file_format.first_ifd_val()))?;
// let first_ifd = BigTiffIFD::read(&mut for_ifd).unwrap();
// let mut ifd_ptrs = IFDPtrIterator::new(
// &mut file,
// file_format.first_ifd_val()
// );
// for_ifd.seek(std::io::SeekFrom::Start(ifd_ptrs.last_complete().unwrap()))?;
// let last_ifd = BigTiffIFD::read(&mut for_ifd).unwrap();

// let first = get_epoch_timestamps_laser(&[&first_ifd], &mut file)[0];
// let last = get_epoch_timestamps_laser(&[&last_ifd], &mut file)[0];

// Ok((first, last))
}

/// `get_frames(path, frames, registration)` returns the intensity data of the
Expand Down Expand Up @@ -366,6 +463,23 @@ mod tests {
assert!(reader.unwrap().filename().contains("BarOnAtTen_1.siff"));
}

#[test]
fn test_scan_timestamps(){
let timestamps = scan_timestamps(&TEST_FILE_PATH);
assert!(timestamps.is_ok());
let (start, end) = timestamps.unwrap();
assert!(start <= end);
assert_ne!(start, 0);
assert_ne!(end, 0);

let first = scan_first_timestamp(&TEST_FILE_PATH);

assert!(first.is_ok());
assert_eq!(first.unwrap(), start);

println!("Start: {}, End: {}", start, end);
}

#[test]
fn test_siff_to_tiff() {

Expand Down
63 changes: 0 additions & 63 deletions src/siffreader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use std::{
};

use binrw::io::BufReader;
use binrw::BinRead;
use itertools::izip;
use ndarray::prelude::*;
use rayon::prelude::*;
Expand All @@ -28,7 +27,6 @@ use crate::{
BigTiffIFD,
IFD,
dimensions_consistent,
IFDPtrIterator,
},
data::image::{
load::*,
Expand Down Expand Up @@ -138,56 +136,6 @@ impl SiffReader{
)
}

/// A fast parse that returns just the first and last timestamps in the file.
/// Uses the system timestamps.
///
/// ## Arguments
///
/// * `filename` - A string slice that holds the name of the file to open
///
/// ## Returns
///
/// * `Result<(u64, u64), CorrosiffError>` - A tuple of two `u64` values
/// corresponding to the first and last timestamps in the file in epoch
/// time (seconds since 1970-01-01 00:00:00 UTC).
pub fn scan_timestamps<P: AsRef<Path>>(filename: P) -> Result<(u64, u64), CorrosiffError> {
let mut file = File::open(&filename)?;
// let mut buff = BufReader::new(&file);
let file_format = {
FileFormat::minimal_filetype(&mut file)
.map_err(|e| CorrosiffError::FileFormatError)
}?;

// let mut for_ifd = std::fs::File::open(&filename)?;
// for_ifd.seek(std::io::SeekFrom::Start(file_format.first_ifd_val()))?;
// let first_ifd = BigTiffIFD::read(&mut for_ifd).unwrap();
// let mut ifd_ptrs = IFDPtrIterator::new(
// &mut file,
// file_format.first_ifd_val()
// );
// for_ifd.seek(std::io::SeekFrom::Start(ifd_ptrs.last_complete().unwrap()))?;
// let last_ifd = BigTiffIFD::read(&mut for_ifd).unwrap();

// let first = get_epoch_timestamps_laser(&[&first_ifd], &mut file)[0];
// let last = get_epoch_timestamps_laser(&[&last_ifd], &mut file)[0];

// Ok((first, last))
let mut wee_buff = BufReader::with_capacity(400, &file);
let mut ifds = file_format.get_ifd_iter(&mut wee_buff);
let (first, last) = (
get_epoch_timestamps_laser(
&[&ifds.next().ok_or_else(||CorrosiffError::FileFormatError)?],
&mut ifds.reader
)[0],
get_epoch_timestamps_laser(
&[&ifds.last().ok_or_else(||CorrosiffError::FileFormatError)?],
&mut file
)[0]
);

Ok((first, last))
}

/// Returns number of frames in the file
/// (including flyback etc).
pub fn num_frames(&self) -> usize {
Expand Down Expand Up @@ -2378,17 +2326,6 @@ mod tests {
assert!(reader.is_ok());
}

#[test]
fn test_scan_timestamps(){
let timestamps = SiffReader::scan_timestamps(TEST_FILE_PATH);
assert!(timestamps.is_ok());
let (start, end) = timestamps.unwrap();
assert!(start <= end);
assert_ne!(start, 0);
assert_ne!(end, 0);
println!("Start: {}, End: {}", start, end);
}

#[test]
fn read_frame() {
let reader = SiffReader::open(TEST_FILE_PATH).unwrap();
Expand Down
2 changes: 2 additions & 0 deletions src/tiff/ifd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,10 @@ impl <'a, S> Iterator for IFDPtrIterator<'a, S>
let mut num_tags = vec![0u8; 8];
self.reader.read_exact(&mut num_tags).ok()?;
let num_tags = bytemuck::cast_slice::<u8, u64>(&num_tags).first().unwrap().clone();
// let num_tags = 19;
let tag_size = 20 as u64;

// self.reader.seek(SeekFrom::Start(self.to_next + num_tags*tag_size)).ok()?;
self.reader.seek(SeekFrom::Current((num_tags * tag_size) as i64)).ok()?;
let mut next_ifd = vec![0; 8];
self.reader.read_exact(&mut next_ifd).ok()?;
Expand Down
11 changes: 11 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ impl From<std::io::Error> for FramesError {
}
}

impl From<binrw::Error> for FramesError {
fn from(err : binrw::Error) -> Self {
FramesError::IOError(
std::io::Error::new(
std::io::ErrorKind::InvalidData,
err.to_string()
)
)
}
}

impl std::error::Error for FramesError {}

impl std::fmt::Display for FramesError {
Expand Down

0 comments on commit ac104fb

Please sign in to comment.