gpt4 book ai didi

rust - 如何分配与高速缓存行的大小对齐的Vec

转载 作者:行者123 更新时间:2023-12-03 11:30:14 27 4
gpt4 key购买 nike

我需要分配一个缓冲区以便从File读取,但是此缓冲区必须与高速缓存行的大小(64字节)对齐。我正在为Vec寻找类似这样的功能:

pub fn with_capacity_and_aligned(capacity: usize, alignment: u8) -> Vec<T>

这将给我所需的64字节对齐方式。这显然不存在,但是可能存在一些我不知道的等效项(即“hacks”)。

因此,当我使用此函数(它将为我提供所需的对齐方式)时,可以安全地编写以下代码:
#[repr(C)]
struct Header {
magic: u32,
some_data1: u32,
some_data2: u64,
}

let cache_line_size = 64; // bytes
let buffer: Vec<u8> = Vec::<u8>::with_capacity_and_alignment(some_size, cache_line_size);
match file.read_to_end(&mut buffer) {
Ok(_) => {
let header: Header = {
// and since the buffer is aligned to 64 bytes, I wont get any SEGFAULT
unsafe { transmute(buffer[0..(size_of::<Header>())]) }
};
}
}

并且由于对齐问题( like launching an instruction)不会出现任何 panic 。

最佳答案

您可以使用#[repr(align(...))]将类型的对齐方式强制为特定大小。我们还使用repr(C)来确保此类型与字节数组具有相同的内存布局。

然后,您可以创建对齐类型的向量,并将其转换为适当类型的向量:

use std::mem;

#[repr(C, align(64))]
struct AlignToSixtyFour([u8; 64]);

unsafe fn aligned_vec(n_bytes: usize) -> Vec<u8> {
// Lazy math to ensure we always have enough.
let n_units = (n_bytes / mem::size_of::<AlignToSixtyFour>()) + 1;

let mut aligned: Vec<AlignToSixtyFour> = Vec::with_capacity(n_units);

let ptr = aligned.as_mut_ptr();
let len_units = aligned.len();
let cap_units = aligned.capacity();

mem::forget(aligned);

Vec::from_raw_parts(
ptr as *mut u8,
len_units * mem::size_of::<AlignToSixtyFour>(),
cap_units * mem::size_of::<AlignToSixtyFour>(),
)
}

如果您重新分配数据,则不能保证 Vec<u8>保持对齐。这意味着您无法重新分配,因此您需要知道要预先分配的空间。

出于相同的原因,该函数是 unsafe。删除类型时,使用 the memory must be back to its original allocation,但此函数无法控制它。

感谢BurntSushi5的 corrections and additions

也可以看看:
  • How can I align a struct to a specifed byte boundary?
  • Align struct to cache lines in Rust
  • How do I convert a Vec<T> to a Vec<U> without copying the vector?

  • 由于上述限制和不安全性,另一个潜在的想法是分配一个足够大的缓冲区(可能有一些摆动空间),然后使用 align_to 获得正确对齐的块。您可以使用与上述相同的 AlignToSixtyFour类型,然后将 &[AlignToSixtyFour]转换为具有类似逻辑的 &[u8]

    该技术可用于给出对齐的(可选可变的)切片。由于它们是切片,因此您不必担心用户重新分配或删除它们。这将允许您将其包装为更好的类型。

    话虽如此,我认为在这里依靠对齐方式并不适合您实际从文件中读取结构的目标。只需读取字节( u32u32u64)并构建结构:
    use byteorder::{LittleEndian, ReadBytesExt}; // 1.3.4
    use std::{fs::File, io};

    #[derive(Debug)]
    struct Header {
    magic: u32,
    some_data1: u32,
    some_data2: u64,
    }

    impl Header {
    fn from_reader(mut reader: impl io::Read) -> Result<Self, Box<dyn std::error::Error>> {
    let magic = reader.read_u32::<LittleEndian>()?;
    let some_data1 = reader.read_u32::<LittleEndian>()?;
    let some_data2 = reader.read_u64::<LittleEndian>()?;

    Ok(Self {
    magic,
    some_data1,
    some_data2,
    })
    }
    }

    fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut f = File::open("/etc/hosts")?;

    let header = Header::from_reader(&mut f)?;

    println!("{:?}", header);

    Ok(())
    }

    也可以看看:
  • How to read a struct from a file in Rust?
  • Is this the most natural way to read structs from a binary file?
  • Can I take a byte array and deserialize it into a struct?
  • Transmuting u8 buffer to struct in Rust
  • 关于rust - 如何分配与高速缓存行的大小对齐的Vec <u8>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60180121/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com