From d474cf58a5876bd214fa9cb68adf9dc8e2e36489 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Mon, 24 Aug 2020 16:20:42 +0800 Subject: [PATCH] runtime/rpc: optimizations for list and arrays Requires https://github.com/m-labs/artiq/pull/1510 This is the commit producing the result in the table. --- src/runtime/src/rpc.rs | 150 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 136 insertions(+), 14 deletions(-) diff --git a/src/runtime/src/rpc.rs b/src/runtime/src/rpc.rs index e558425d..bb8cfd22 100644 --- a/src/runtime/src/rpc.rs +++ b/src/runtime/src/rpc.rs @@ -2,6 +2,7 @@ use core::str; use core::future::Future; use cslice::{CSlice, CMutSlice}; use log::trace; +use byteorder::{NetworkEndian, ByteOrder}; use core_io::{Write, Error}; use libboard_zynq::smoltcp; @@ -76,14 +77,40 @@ async unsafe fn recv_value(stream: &TcpStream, tag: Tag<'async_recursion>, da #[repr(C)] struct List { elements: *mut (), length: u32 }; consume_value!(List, |ptr| { - (*ptr).length = proto_async::read_i32(stream).await? as u32; - + let length = proto_async::read_i32(stream).await? as usize; + (*ptr).length = length as u32; let tag = it.clone().next().expect("truncated tag"); - (*ptr).elements = alloc(tag.size() * (*ptr).length as usize).await; + let mut data = alloc(tag.size() * length as usize).await; - let mut data = (*ptr).elements; - for _ in 0..(*ptr).length as usize { - recv_value(stream, tag, &mut data, alloc).await? + (*ptr).elements = data; + match tag { + Tag::Bool => { + let ptr = align_ptr_mut::(data); + let dest = core::slice::from_raw_parts_mut(ptr, length); + proto_async::read_chunk(stream, dest).await?; + }, + Tag::Int32 => { + let ptr = align_ptr_mut::(data); + // reading as raw bytes and do endianness conversion later + let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 4); + proto_async::read_chunk(stream, dest).await?; + drop(dest); + let dest = core::slice::from_raw_parts_mut(ptr, length); + NetworkEndian::from_slice_u32(dest); + }, + Tag::Int64 | Tag::Float64 => { + let ptr = align_ptr_mut::(data); + let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 8); + proto_async::read_chunk(stream, dest).await?; + drop(dest); + let dest = core::slice::from_raw_parts_mut(ptr, length); + NetworkEndian::from_slice_u64(dest); + }, + _ => { + for _ in 0..(*ptr).length as usize { + recv_value(stream, tag, &mut data, alloc).await? + } + } } Ok(()) }) @@ -100,9 +127,35 @@ async unsafe fn recv_value(stream: &TcpStream, tag: Tag<'async_recursion>, da let elt_tag = it.clone().next().expect("truncated tag"); *buffer = alloc(elt_tag.size() * total_len as usize).await; + let length = total_len as usize; let mut data = *buffer; - for _ in 0..total_len { - recv_value(stream, elt_tag, &mut data, alloc).await? + match elt_tag { + Tag::Bool => { + let ptr = align_ptr_mut::(data); + let dest = core::slice::from_raw_parts_mut(ptr, length); + proto_async::read_chunk(stream, dest).await?; + }, + Tag::Int32 => { + let ptr = align_ptr_mut::(data); + let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 4); + proto_async::read_chunk(stream, dest).await?; + drop(dest); + let dest = core::slice::from_raw_parts_mut(ptr, length); + NetworkEndian::from_slice_u32(dest); + }, + Tag::Int64 | Tag::Float64 => { + let ptr = align_ptr_mut::(data); + let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 8); + proto_async::read_chunk(stream, dest).await?; + drop(dest); + let dest = core::slice::from_raw_parts_mut(ptr, length); + NetworkEndian::from_slice_u64(dest); + }, + _ => { + for _ in 0..length { + recv_value(stream, elt_tag, &mut data, alloc).await? + } + } } Ok(()) }) @@ -177,12 +230,47 @@ unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) #[repr(C)] struct List { elements: *const (), length: u32 }; consume_value!(List, |ptr| { + let length = (*ptr).length as isize; writer.write_u32((*ptr).length)?; let tag = it.clone().next().expect("truncated tag"); let mut data = (*ptr).elements; - for _ in 0..(*ptr).length as usize { - send_value(writer, tag, &mut data)?; - } + writer.write_u8(tag.as_u8())?; + match tag { + Tag::Bool => { + // we can pretend this is u8... + let ptr1 = align_ptr::(data); + let slice = core::slice::from_raw_parts(ptr1, length as usize); + writer.write_all(slice)?; + }, + Tag::Int32 => { + let ptr1 = align_ptr::(data); + let slice = core::slice::from_raw_parts(ptr1, length as usize); + let mut v: alloc::vec::Vec = slice.to_vec(); + NetworkEndian::from_slice_i32(&mut v); + let slice2 = core::slice::from_raw_parts( + v.as_ptr() as usize as *const u8, + length as usize * 4 + ); + writer.write_all(slice2)?; + }, + Tag::Int64 | Tag::Float64 => { + let ptr1 = align_ptr::(data); + let slice = core::slice::from_raw_parts(ptr1, length as usize); + let mut v: alloc::vec::Vec = slice.to_vec(); + NetworkEndian::from_slice_i64(&mut v); + let slice2 = core::slice::from_raw_parts( + v.as_ptr() as usize as *const u8, + length as usize * 8 + ); + writer.write_all(slice2)?; + }, + // non-primitive types, not sure if this would happen but we can handle it... + _ => { + for _ in 0..length { + send_value(writer, tag, &mut data)?; + } + } + }; Ok(()) }) } @@ -199,9 +287,43 @@ unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) }) } let mut data = *buffer; - for _ in 0..total_len as usize { - send_value(writer, elt_tag, &mut data)?; - } + let length = total_len as isize; + writer.write_u8(elt_tag.as_u8())?; + match elt_tag { + Tag::Bool => { + let ptr1 = align_ptr::(data); + let slice = core::slice::from_raw_parts(ptr1, length as usize); + writer.write_all(slice)?; + }, + Tag::Int32 => { + let ptr1 = align_ptr::(data); + let slice = core::slice::from_raw_parts(ptr1, length as usize); + let mut v: alloc::vec::Vec = slice.to_vec(); + NetworkEndian::from_slice_i32(&mut v); + let slice2 = core::slice::from_raw_parts( + v.as_ptr() as usize as *const u8, + length as usize * 4 + ); + writer.write_all(slice2)?; + }, + Tag::Int64 | Tag::Float64 => { + let ptr1 = align_ptr::(data); + let slice = core::slice::from_raw_parts(ptr1, length as usize); + let mut v: alloc::vec::Vec = slice.to_vec(); + NetworkEndian::from_slice_i64(&mut v); + let slice2 = core::slice::from_raw_parts( + v.as_ptr() as usize as *const u8, + length as usize * 8 + ); + writer.write_all(slice2)?; + }, + // non-primitive types, not sure if this would happen but we can handle it... + _ => { + for _ in 0..length { + send_value(writer, elt_tag, &mut data)?; + } + } + }; Ok(()) }) }