【发布时间】:2019-02-17 16:18:19
【问题描述】:
我需要对 32 kbit 宽的数据执行按位与。这些值之一是固定位掩码。
我一次执行这个 AND 32 位。简化后,我的算法将如下所示:
(我将从此示例中删除内存管理、变量范围问题等)
#include <stdint.h>
const uint32_t mask[1024] = {
0b00110110100101100111001011000111,
0b10001110100101111010010100100100,
0b11101010010000110001101010010101,
0b10001110100101111010010100100100,
(...) // 1019 more lines!
0b00110110100101100111001011000111};
uint32_t answer[1024] = {0};
uint32_t workingdata = 0;
uint16_t i = 0;
int main(void)
{
for (i=0; i<1024; i++)
{
workingdata = getnextdatachunk();
answer[i] = workingdata & mask[i];
}
do_something_with_answer();
return 0;
}
事情是这样的:如果您查看示例位掩码,掩码 [1] == 掩码 [3] 和掩码 [0] == 掩码 [1023]。
在我的实际位掩码中,大多数值都是重复的;整个 1024 值数组中只有 20 个不同的值。此外,在我的最终应用程序中我有 16 个不同的位掩码,每个位掩码都有相似的内部重复。
我正在寻找一种避免存储和遍历大量不必要数据的好方法。
我考虑过的一种方法类似于查找表,其中我的数组仅包含每个所需位掩码块的单个实例:
const uint32_t mask[20] = {
0b00110110100101100111001011000111,
0b10001110100101111010010100100100,
(...) // only 17 more lines!
0b11101010010000110001101010010101};
uint32_t answer[1024] = {0};
uint32_t workingdata = 0;
uint16_t i = 0;
int main(void)
{
for (i=0; i<1024; i++)
{
workingdata = getnextdata();
switch(i)
{
// the mask indexes are precalculated:
case 0:
answer[i] = workingdata & mask[5];
break;
case 1:
answer[i] = workingdata & mask[2];
break;
case 2:
answer[i] = workingdata & mask[2];
break;
case 3:
answer[i] = workingdata & mask[0];
break;
case (...): // 1020 more cases!
(...);
break;
default:
}
}
do_something_with_answer();
return 0;
}
或者,使用更紧凑的 switch 语句:
switch(i)
{
// the mask indexes are precalculated:
case 0,3,4,5,18,35,67,(...),1019:
answer[i] = workingdata & mask[0];
break;
case 1,15,16,55,89,91,(...),1004:
answer[i] = workingdata & mask[1];
break;
case (...): // Only 18 more cases!
(...);
break;
default:
}
这两种解决方案确实让人不清楚发生了什么,我真的很想避免这种情况。
理想情况下,我想保留原始结构并让 gcc 的优化器删除所有不必要的数据。 如何让我的代码保持良好的编写并仍然高效?
【问题讨论】:
-
我认为您的任何解决方案都不清楚。如果你用 1-2 行注释来限定它,我会很清楚。如果您要执行 switch 语句路由,可能会预先计算您的值并将它们保存为标题中的#define(s),然后包含它。
-
原来的解决方案有那么糟糕吗? 32kbits 是 4 KB,适合 L1 缓存。可能有一些方法可以压缩它(例如两层查找表),但这些方法可能比用愚蠢、简单的方法来做要慢。
-
所有优化都会导致权衡取舍,最常见的是更快但使用更多内存,或者更慢但使用更少内存。而所有优化将导致代码难以阅读、遵循、理解和维护。在你的情况下,我建议你保留你的大表,否则代码将难以理解,甚至可能占用更多空间,甚至可能更慢。
-
最重要的是:在您测量代码是您程序中的前三大瓶颈之前,不要进行优化。并且始终在启用编译器优化的情况下进行测量。
-
谢谢@NickODell!在原始问题中并不明显(我只是进行了编辑以使其更明显),但实际上我有 16 个这样的位掩码。但也许它仍然不值得调整:)
标签: c gcc optimization