将字节打包成 u32 与将它们存储在 vec<u8> 中的性能差异?
Performance difference between bitpacking bytes into a u32 vs storing them in a vec<u8>?
简介:
我很好奇将小数字存储为位压缩无符号整数与字节向量的性能差异(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 >> 24
和&v[0]
这两个表达式。我不知道 rust 在位移位和从堆中获取值之间的速度有多快。我会测试它,但我暂时无法使用安装了 Rust 的机器。有人可以就这两种操作的缺点给出任何直接的见解吗?
问题 3
最后,内存使用的区别是否简单到只在堆栈上为 u32
存储 32 位与在堆栈上为指针 v
存储 64 位以及 32 位在 v
?
的堆上
抱歉,如果这个问题有点令人困惑
使用Vec
会更贵;正如您提到的,它将需要执行堆分配,并且还将对访问进行边界检查。
也就是说,如果您改用数组 [u8; 4]
,与位压缩 u32
表示相比的性能应该几乎相同。
事实上,请考虑以下简单示例:
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,u32
与 [u8; 4]
对于这些类型的操作的性能通常应该是相同的。
tl;dr 使用结构:
struct Color {
r: u8,
g: u8,
b: u8,
a: u8,
}
也许也可以使用 repr(packed)
。
它为您提供世界上最好的东西,您可以为频道命名。
Are these costs significant enough to make bit packing worth it?
堆分配有巨大成本。
Are there any immediate insights someone could give on the drawbacks of these two operations?
与分配内存相比,两者都是噪音。
简介:
我很好奇将小数字存储为位压缩无符号整数与字节向量的性能差异(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 >> 24
和&v[0]
这两个表达式。我不知道 rust 在位移位和从堆中获取值之间的速度有多快。我会测试它,但我暂时无法使用安装了 Rust 的机器。有人可以就这两种操作的缺点给出任何直接的见解吗?
问题 3
最后,内存使用的区别是否简单到只在堆栈上为 u32
存储 32 位与在堆栈上为指针 v
存储 64 位以及 32 位在 v
?
抱歉,如果这个问题有点令人困惑
使用Vec
会更贵;正如您提到的,它将需要执行堆分配,并且还将对访问进行边界检查。
也就是说,如果您改用数组 [u8; 4]
,与位压缩 u32
表示相比的性能应该几乎相同。
事实上,请考虑以下简单示例:
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,u32
与 [u8; 4]
对于这些类型的操作的性能通常应该是相同的。
tl;dr 使用结构:
struct Color {
r: u8,
g: u8,
b: u8,
a: u8,
}
也许也可以使用 repr(packed)
。
它为您提供世界上最好的东西,您可以为频道命名。
Are these costs significant enough to make bit packing worth it?
堆分配有巨大成本。
Are there any immediate insights someone could give on the drawbacks of these two operations?
与分配内存相比,两者都是噪音。