1

介绍:

我很好奇将小数字存储为位压缩无符号整数与字节向量的性能差异(cpu 和内存使用)

例子

我将使用存储 RGBA 值的示例。它们是 4 字节,因此很容易将它们存储为u32.
但是,将它们存储为类型的向量会更具可读性u8


作为更详细的示例,假设我想存储和检索颜色 rgba(255,0,0,255)

这就是我将如何去做这两种方法:

// Bitpacked:
let i: u32 = 4278190335;
//binary is 11111111 00000000 00000000 11111111
//In reality I would most likely do something more similar to:
let i: u32 = 255 << 24 + 255; //i think this syntax is right

// Vector:
let v: Vec<u8> = [255,0,0,255];

然后可以查询两个红色值

i >> 24 
//or
&v[0]
//both expressions evaluate to 255 (i think. I'm really new to rust <3 )

问题 1

据我所知, 的值v必须存储在堆上,因此存在与之相关的性能成本。这些成本是否足以使钻头包装物有所值?

问题2

然后是两个表达式i >> 24and &v[0]。我不知道 rust 在位移和从堆中获取值的速度有多快。我会对其进行测试,但我暂时无法使用安装了 rust 的机器。有人可以就这两个操作的缺点提供任何直接的见解吗?

问题 3

最后,内存使用的差异是否简单到只在堆栈上存储 32 位与在堆栈上u32存储 64 位作为指针v以及在堆上存储 32 位的值v

对不起,如果这个问题有点令人困惑

4

2 回答 2

5

使用 aVec会更贵;正如您所提到的,它将需要执行堆分配,并且访问也将受到边界检查。

也就是说,如果您改用数组[u8; 4],则与 bitpackedu32表示相比的性能应该几乎相同。

实际上,请考虑以下简单示例:

pub fn get_red_bitpacked(i: u32) -> u8 {
    (i >> 24) as u8
}

pub fn get_red_array(v: [u8; 4]) -> u8 {
    v[3]
}

pub fn test_bits(colour: u8) -> u8 {
    let colour = colour as u32;
    let i = (colour << 24) + colour;
    get_red_bitpacked(i)
}

pub fn test_arr(colour: u8) -> u8 {
    let v = [colour, 0, 0, colour];
    get_red_array(v)
}

我看了一下Compiler Explorer,编译器决定了这一点get_red_bitpacked并且get_red_array完全相同:如此之多以至于它甚至都没有为前者生成代码。这两个“测试”功能显然也针对完全相同的程序集进行了优化。

example::get_red_array:
        mov     eax, edi
        shr     eax, 24
        ret

example::test_bits:
        mov     eax, edi
        ret

example::test_arr:
        mov     eax, edi
        ret

显然,这个例子被编译器看穿了:为了进行适当的比较,您应该用实际代码进行基准测试。话虽如此,我可以相当肯定地说,对于 Rust ,这些操作的u32vs性能通常应该是相同的。[u8; 4]

于 2021-06-02T04:21:12.347 回答
0

tl;博士使用结构:

struct Color {
    r: u8,
    g: u8,
    b: u8,
    a: u8,
}

也许也可以使用repr(packed)

它为您提供了世界上最好的,您可以为频道命名。

这些成本是否足以使钻头包装物有所值?

堆分配具有巨大的成本。

有人可以就这两个操作的缺点提供任何直接的见解吗?

与分配内存相比,两者都是噪音。

于 2021-06-02T04:47:47.237 回答