diff --git a/benches/fs_open_close.rs b/benches/fs_open_close.rs index b0d2ec73d..d000dbf9e 100644 --- a/benches/fs_open_close.rs +++ b/benches/fs_open_close.rs @@ -43,7 +43,8 @@ pub fn run_benchmark(c: &mut Criterion) { group.bench_function("TF01: Lind open+close", |b| { b.iter(|| { let fd = cage.open_syscall("foo", O_CREAT | O_TRUNC | O_WRONLY, S_IRWXA); - cage.close_syscall(fd); + assert!(fd > 2); // Ensure we didn't get an error or an odd fd + assert_eq!(cage.close_syscall(fd), 0); // close the file w/o error }) }); @@ -55,7 +56,8 @@ pub fn run_benchmark(c: &mut Criterion) { O_CREAT | O_TRUNC | O_WRONLY, S_IRWXA, ); - libc::close(fd); + assert!(fd > 2); // Ensure we didn't get an error or an odd fd + assert_eq!(libc::close(fd), 0); // close the file w/o error }) }); group.finish(); diff --git a/benches/fs_read_write.rs b/benches/fs_read_write.rs index dcf73b911..0c57de4d3 100644 --- a/benches/fs_read_write.rs +++ b/benches/fs_read_write.rs @@ -54,20 +54,53 @@ pub fn run_benchmark(c: &mut Criterion) { &String::from_utf8(vec![b'X'; *buflen]).expect("error building string"), ); - let fd = cage.open_syscall("foo", O_CREAT | O_TRUNC | O_WRONLY, S_IRWXA); + // The size of the buffer and the amount we expect to read and write. + let expected_retval = *buflen as i32; + + // My current position when writing... + let mut pos = 0; + + // Rather than track the file size, I will reset after a fixed amount + // of data is written. This is to avoid https://github.com/Lind-Project/safeposix-rust/issues/241 + // Once that bug is fixed, I should model the code used for Native + // and just track how much write has written, using this to know when + // to reset + const RESET_LENGTH: i32 = 1024 * 1024 * 4; // 4MB + + // Did I make it to the reset length? If not I will later abort so + // that I ensure I have enough to read. + let mut reached_reset_length: bool = false; + + let fd = cage.open_syscall("foo", O_CREAT | O_TRUNC | O_RDWR, S_IRWXA); // Let's see how fast various file system calls are group.bench_with_input( BenchmarkId::new("TF02:Lind write", buflen), buflen, |b, buflen| { b.iter(|| { - let _ = cage.write_syscall(fd, deststring, *buflen); + pos += expected_retval; + // pos is the value we expect the pointer to be at AFTER + // the write, so we need < pos here to write until + // RESET_LENGTH + if RESET_LENGTH < pos { + cage.lseek_syscall(fd, 0, SEEK_SET); + pos = 0; + reached_reset_length = true; + } + assert_eq!(cage.write_syscall(fd, deststring, *buflen), expected_retval); }) }, ); + if !reached_reset_length { + panic!("Try decreasing RESET_LENGTH.\nOnly reached {}/{} bytes needed for read in Lind write.",pos,RESET_LENGTH); + } + cage.lseek_syscall(fd, 0, SEEK_SET); + // My current position when reading... + pos = 0; + let mut read_buffer = tests::sizecbuf(*buflen); group.bench_with_input( @@ -75,7 +108,20 @@ pub fn run_benchmark(c: &mut Criterion) { buflen, |b, buflen| { b.iter(|| { - cage.read_syscall(fd, read_buffer.as_mut_ptr(), *buflen); + // Track the file pointer so you can backtrack if you make + // it to the end of the file. This avoids having a bunch + // of garbage, 0 length reads skew the results... + // We use <= here because we can have a read go to the + // expected EOF + pos += expected_retval; + if RESET_LENGTH <= pos { + cage.lseek_syscall(fd, 0, SEEK_SET); + pos = 0; + } + assert_eq!( + cage.read_syscall(fd, read_buffer.as_mut_ptr(), *buflen), + expected_retval + ); }) }, ); @@ -91,10 +137,18 @@ pub fn run_benchmark(c: &mut Criterion) { let fd: c_int; let c_str = CString::new("/tmp/foo").unwrap(); + // The size of the buffer and the amount we expect to read and write. + // I need to type convert this because it's a usize by default. + // I'm lazily converting with as here because it's not feasible to + // test values where usize would overflow this. + // NOTE: This has a different type than Lind, which is i32. I think + // this is likely okay. + let expected_retval = *buflen as isize; + let path = c_str.into_raw() as *const u8; unsafe { - fd = libc::open(path, O_CREAT | O_TRUNC | O_WRONLY, S_IRWXA); + fd = libc::open(path, O_CREAT | O_TRUNC | O_RDWR, S_IRWXA); } let deststring = tests::str2cbuf( @@ -107,15 +161,26 @@ pub fn run_benchmark(c: &mut Criterion) { buflen, |b, buflen| { b.iter(|| unsafe { - let _ = libc::write(fd, deststring as *const c_void, *buflen); + assert_eq!( + libc::write(fd, deststring as *const c_void, *buflen), + expected_retval + ); }) }, ); + // I'll read the file length so I don't overrun this with my reads... + let file_length: isize; unsafe { + file_length = libc::lseek(fd, 0, SEEK_CUR) as isize; + + // reset the file position libc::lseek(fd, 0, SEEK_SET); } + // My current position when reading... + let mut pos = 0; + let mut read_buffer = tests::sizecbuf(*buflen); // For comparison let's time the native OS... @@ -124,7 +189,18 @@ pub fn run_benchmark(c: &mut Criterion) { buflen, |b, buflen| { b.iter(|| unsafe { - libc::read(fd, read_buffer.as_mut_ptr() as *mut c_void, *buflen); + // Track the file pointer so you can backtrack if you make + // it to the end of the file. This avoids having a bunch + // of garbage, 0 length reads skew the results... + pos += expected_retval; + if file_length <= pos { + libc::lseek(fd, 0, SEEK_SET); + pos = 0; + } + assert_eq!( + libc::read(fd, read_buffer.as_mut_ptr() as *mut c_void, *buflen), + expected_retval + ); }) }, ); @@ -141,7 +217,7 @@ pub fn run_benchmark(c: &mut Criterion) { rustposix::safeposix::dispatcher::lindrustfinalize(); } -criterion_group!(name=benches; +criterion_group!(name=benches; // Add the global settings here so we don't type it everywhere config=global_criterion_settings::get_criterion(); targets=run_benchmark); diff --git a/benches/fs_read_write_seek.rs b/benches/fs_read_write_seek.rs index bc7eec58c..676602d28 100644 --- a/benches/fs_read_write_seek.rs +++ b/benches/fs_read_write_seek.rs @@ -47,12 +47,18 @@ pub fn run_benchmark(c: &mut Criterion) { // Iterate for different buffer sizes... for buflen in [1, 64, 1024, 65536].iter() { - let fd = cage.open_syscall("foo", O_CREAT | O_TRUNC | O_WRONLY, S_IRWXA); + let fd = cage.open_syscall("foo", O_CREAT | O_TRUNC | O_RDWR, S_IRWXA); let deststring = tests::str2cbuf( &String::from_utf8(vec![b'X'; *buflen]).expect("error building string"), ); + // The size of the buffer and the amount we expect to read and write. + // I need to type convert this because it's a usize by default. + // I'm lazily converting with as here because it's not feasible to + // test values where usize would overflow this. + let expected_retval = *buflen as i32; + let read_buffer = tests::sizecbuf(*buflen).as_mut_ptr(); // Let's see how fast various file system calls are group.bench_with_input( @@ -60,10 +66,10 @@ pub fn run_benchmark(c: &mut Criterion) { buflen, |b, buflen| { b.iter(|| { - let _ = cage.write_syscall(fd, deststring, *buflen); - cage.lseek_syscall(fd, 0, SEEK_SET); - cage.read_syscall(fd, read_buffer, *buflen); - cage.lseek_syscall(fd, 0, SEEK_SET); + assert_eq!(cage.write_syscall(fd, deststring, *buflen), expected_retval); + assert_eq!(cage.lseek_syscall(fd, 0, SEEK_SET), 0); + assert_eq!(cage.read_syscall(fd, read_buffer, *buflen), expected_retval); + assert_eq!(cage.lseek_syscall(fd, 0, SEEK_SET), 0); }) }, ); @@ -83,7 +89,7 @@ pub fn run_benchmark(c: &mut Criterion) { let path = c_str.into_raw() as *const u8; unsafe { - fd = libc::open(path, O_CREAT | O_TRUNC | O_WRONLY, S_IRWXA); + fd = libc::open(path, O_CREAT | O_TRUNC | O_RDWR, S_IRWXA); } let deststring = tests::str2cbuf( @@ -92,16 +98,30 @@ pub fn run_benchmark(c: &mut Criterion) { let read_buffer = tests::sizecbuf(*buflen).as_mut_ptr(); + // The size of the buffer and the amount we expect to read and write. + // I need to type convert this because it's a usize by default. + // I'm lazily converting with as here because it's not feasible to + // test values where usize would overflow this. + // NOTE: This has a different type than Lind, which is i32. I think + // this is likely okay. + let expected_retval = *buflen as isize; + // For comparison let's time the native OS... group.bench_with_input( BenchmarkId::new("TF03:Native write+read+lseek", buflen), buflen, |b, buflen| { b.iter(|| unsafe { - let _ = libc::write(fd, deststring as *const c_void, *buflen); - libc::lseek(fd, 0, SEEK_SET); - libc::read(fd, read_buffer as *mut c_void, *buflen); - libc::lseek(fd, 0, SEEK_SET); + assert_eq!( + libc::write(fd, deststring as *const c_void, *buflen), + expected_retval + ); + assert_eq!(libc::lseek(fd, 0, SEEK_SET), 0); + assert_eq!( + libc::read(fd, read_buffer as *mut c_void, *buflen), + expected_retval + ); + assert_eq!(libc::lseek(fd, 0, SEEK_SET), 0); }) }, ); @@ -118,7 +138,7 @@ pub fn run_benchmark(c: &mut Criterion) { rustposix::safeposix::dispatcher::lindrustfinalize(); } -criterion_group!(name=benches; +criterion_group!(name=benches; // Add the global settings here so we don't type it everywhere config=global_criterion_settings::get_criterion(); targets=run_benchmark);