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

[runtime] Enhancement: Create into_buf in the MemoryRuntime #1183

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
6 changes: 4 additions & 2 deletions src/rust/demikernel/libos/network/libos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,9 @@ impl<T: NetworkTransport> SharedNetworkLibOS<T> {
/// coroutine that asynchronously runs the push and any synchronous multi-queue functionality before the push
/// begins.
pub fn push(&mut self, qd: QDesc, sga: &demi_sgarray_t) -> Result<QToken, Fail> {
let buf: DemiBuffer = self.transport.clone_sgarray(sga)?;
trace!("push() qd={:?}", qd);

let buf: DemiBuffer = self.transport.into_buf(sga)?;
if buf.len() == 0 {
let cause: String = format!("zero-length buffer");
warn!("push(): {}", cause);
Expand Down Expand Up @@ -400,7 +402,7 @@ impl<T: NetworkTransport> SharedNetworkLibOS<T> {
pub fn pushto(&mut self, qd: QDesc, sga: &demi_sgarray_t, remote: SocketAddr) -> Result<QToken, Fail> {
trace!("pushto() qd={:?}", qd);

let buf: DemiBuffer = self.transport.clone_sgarray(sga)?;
let buf: DemiBuffer = self.transport.into_buf(sga)?;
if buf.len() == 0 {
return Err(Fail::new(libc::EINVAL, "zero-length buffer"));
}
Expand Down
116 changes: 82 additions & 34 deletions src/rust/runtime/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,28 @@ pub trait MemoryRuntime {
})
}

/// Converts a scatter-gather array into a buffer.
fn into_buf(&self, sga: &demi_sgarray_t) -> Result<DemiBuffer, Fail> {
// Check arguments.
// TODO: Drop this check once we support scatter-gather arrays with multiple segments.
if sga.sga_numsegs != 1 {
return Err(Fail::new(libc::EINVAL, "demi_sgarray_t has invalid segment count"));
}

if sga.sga_buf == ptr::null_mut() {
return Err(Fail::new(libc::EINVAL, "demi_sgarray_t has invalid DemiBuffer token"));
}

// Convert back to a DemiBuffer
// Safety: The `NonNull::new_unchecked()` call is safe, as we verified `sga.sga_buf` is not null above.
let token: NonNull<u8> = unsafe { NonNull::new_unchecked(sga.sga_buf as *mut u8) };
// Safety: The `DemiBuffer::from_raw()` call *should* be safe, as the `sga_buf` field in the `demi_sgarray_t`
// contained a valid `DemiBuffer` token when we provided it to the user (and the user shouldn't change it).
let buf: DemiBuffer = unsafe { DemiBuffer::from_raw(token) };

Ok(buf)
}

/// Allocates a scatter-gather array.
fn sgaalloc(&self, size: usize) -> Result<demi_sgarray_t, Fail> {
// TODO: Allocate an array of buffers if requested size is too large for a single buffer.
Expand Down Expand Up @@ -98,45 +120,18 @@ pub trait MemoryRuntime {

/// Releases a scatter-gather array.
fn sgafree(&self, sga: demi_sgarray_t) -> Result<(), Fail> {
// Check arguments.
// TODO: Drop this check once we support scatter-gather arrays with multiple segments.
if sga.sga_numsegs != 1 {
return Err(Fail::new(libc::EINVAL, "demi_sgarray_t has invalid segment count"));
}

if sga.sga_buf == ptr::null_mut() {
return Err(Fail::new(libc::EINVAL, "demi_sgarray_t has invalid DemiBuffer token"));
match self.into_buf(&sga) {
iyzhang marked this conversation as resolved.
Show resolved Hide resolved
Ok(buf) => {
drop(buf);
Ok(())
},
Err(e) => Err(e),
}

// Convert back to a DemiBuffer and drop it.
// Safety: The `NonNull::new_unchecked()` call is safe, as we verified `sga.sga_buf` is not null above.
let token: NonNull<u8> = unsafe { NonNull::new_unchecked(sga.sga_buf as *mut u8) };
// Safety: The `DemiBuffer::from_raw()` call *should* be safe, as the `sga_buf` field in the `demi_sgarray_t`
// contained a valid `DemiBuffer` token when we provided it to the user (and the user shouldn't change it).
let buf: DemiBuffer = unsafe { DemiBuffer::from_raw(token) };
drop(buf);

Ok(())
}

/// Clones a scatter-gather array.
fn clone_sgarray(&self, sga: &demi_sgarray_t) -> Result<DemiBuffer, Fail> {
// Check arguments.
// TODO: Drop this check once we support scatter-gather arrays with multiple segments.
if sga.sga_numsegs != 1 {
return Err(Fail::new(libc::EINVAL, "demi_sgarray_t has invalid segment count"));
}

if sga.sga_buf == ptr::null_mut() {
return Err(Fail::new(libc::EINVAL, "demi_sgarray_t has invalid DemiBuffer token"));
}

// Convert back to a DemiBuffer.
// Safety: The `NonNull::new_unchecked()` call is safe, as we verified `sga.sga_buf` is not null above.
let token: NonNull<u8> = unsafe { NonNull::new_unchecked(sga.sga_buf as *mut u8) };
// Safety: The `DemiBuffer::from_raw()` call *should* be safe, as the `sga_buf` field in the `demi_sgarray_t`
// contained a valid `DemiBuffer` token when we provided it to the user (and the user shouldn't change it).
let buf: DemiBuffer = unsafe { DemiBuffer::from_raw(token) };
let buf: DemiBuffer = self.into_buf(sga)?;
let mut clone: DemiBuffer = buf.clone();

// Don't drop buf, as it holds the same reference to the data as the sgarray (which should keep it).
Expand Down Expand Up @@ -178,3 +173,56 @@ pub trait MemoryRuntime {
Ok(clone)
}
}

//======================================================================================================================
// Unit Tests
//======================================================================================================================

#[cfg(test)]
mod tests {
use crate::{
expect_ok,
demi_sgarray_t,
runtime::memory::MemoryRuntime,
};
use ::test::{
black_box,
Bencher,
};

// The buffer size.
const BUFSIZE: usize = 1024;

pub struct DummyRuntime { }

impl MemoryRuntime for DummyRuntime {}

#[bench]
fn benchmark_clone_sgarray(b: &mut Bencher) {
let runtime: DummyRuntime = DummyRuntime { };

let sga: demi_sgarray_t = match runtime.sgaalloc(BUFSIZE) {
Ok(sga) => sga,
Err(e) => panic!("failed to allocate sgarray: {:?}", e),
};

b.iter(|| {
black_box(expect_ok!(runtime.clone_sgarray(&sga), "failed to clone sgarray"));
});
}

#[bench]
fn benchmark_into_buf(b: &mut Bencher) {
let runtime: DummyRuntime = DummyRuntime { };

let sga: demi_sgarray_t = match runtime.sgaalloc(BUFSIZE) {
Ok(sga) => sga,
Err(e) => panic!("failed to allocate sgarray: {:?}", e),
};

b.iter(|| {
black_box(expect_ok!(runtime.into_buf(&sga), "failed to convert sgarray"));
});
}

}
Loading