【发布时间】:2026-01-05 16:15:01
【问题描述】:
我有一个循环大约需要 90% 到 99% 的程序时间。它读取了一个巨大的 LUT,并且这个循环被执行了 > 100,000 次,所以它值得一些优化。
编辑:
LUT(实际上有各种组成 LUT 的数组)由 ptrdiff_t 和 unsigned __int128 的数组组成。由于算法(尤其是 128 位的),它们必须那么宽。 T_RDY 是唯一的 bool 数组。
编辑:
LUT 存储过去用于尝试解决无效问题的组合。它们之间没有关系(我还可以看到),所以我没有看到更合适的搜索模式。
循环的单线程版本是:
k = false;
for (ptrdiff_t i = 0; i < T_IND; i++) {
if (T_RDY[i] && !(~T_RWS[i] & M_RWS) && ((T_NUM[i] + P_LVL) <= P_LEN)) {
k = true;
break;
}
}
通过使用 OpenMP 的这段代码,我将 4 核处理器中的时间缩短了 2 倍到 3 倍:
k = false;
#pragma omp parallel for shared(k)
for (ptrdiff_t i = 0; i < T_IND; i++) {
if (k)
continue;
if (T_RDY[i] && !(~T_RWS[i] & M_RWS) && ((T_NUM[i] + P_LVL) <= P_LEN))
k = true;
}
编辑:
关于所用数据的信息:
#define DIM_MAX 128
#define P_LEN prb_lvl[0]
#define P_LVL prb_lvl[1]
#define M_RWS prb_mtx_rws[prb_lvl[1]]
#define T_RWS prb_tab
#define T_NUM prb_tab_num
#define T_RDY prb_tab_rdy
#define T_IND prb_tab_ind
extern ptrdiff_t prb_lvl [2];
extern uint128_t prb_mtx_rws [DIM_MAX];
extern uint128_t prb_tab [10000000];
extern ptrdiff_t prb_tab_num [10000000];
extern bool prb_tab_rdy [10000000];
extern ptrdiff_t prb_tab_ind;
但是,事实上我没有得到大约 10 的改进。 4x 意味着它引入了开销,我猜它是从 2x 到 1.5x。部分开销是不可避免的(创建和销毁线程),但由于 OpenMP 不允许来自并行循环的 break 并且我在每次迭代中添加了 if 和如果可能的话,我想摆脱它。
还有其他可以应用的优化吗?也许改用 pthreads。
我应该麻烦编辑一些程序集吗?
我正在使用 GCC 9 和 -O3 -flto(以及其他)。
编辑:
CPU:i7-5775C
但我计划使用其他具有更多内核的 x64 CPU。
【问题讨论】:
-
评论不用于扩展讨论;这个对话是moved to chat。
-
删除断点可以是:
for (...; !k && ...;...)...... 用于断点的条件。然后你可以使用 k= ... 而不是整个 if 语句。 -
请提供minimal reproducible example 以及具体的性能测量结果。
-
你说它使用了一个查找表(如 1 中),但实际上它使用了 3。它们的大小都相同,可能可以组合成一个查找表桌子。你甚至可以做一个位表,这样你就可以通过比较 0 或 -1(全部为假或全部为真)来一次检查 64 个
-
假设
M_RWS、P_LVL和P_LEN在搜索执行期间不应该更改,您可以将这些外部值加载到局部变量中以确保它们不会每个循环都不断地重新加载。如果您知道P_LEN - P_LVL不会不足或溢出,那么您可以预先计算并在比较中使用它。
标签: c loops pthreads openmp micro-optimization