- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
首先,我有一个数组int a[1000][1000]
。所有这些整数都在0到32767之间,它们是已知的常数:它们在程序运行期间永不改变。
其次,我有一个数组b [32768],其中包含0到32之间的整数。我使用此数组将a中的所有数组映射到32个bin中:
int bins[32]{};
for (auto e : a[i])//mapping a[i] to 32 bins.
bins[b[e]]++;
int new_array[32768] = {some new mapping};
copy(begin(new_array), end(new_array), begin(b));//reload array b;
int bins[1000][32]{};//output array to store results .
for (int i = 0; i < 1000;i++)
for (auto e : a[i])//hashing a[i] to 32 bins.
bins[1000][b[e]]++;
最佳答案
这本质上是一个直方图问题。您正在使用16位查找表映射16位值和5位值,但之后只是对LUT结果进行直方图绘制。有关直方图的更多信息,请参见下文。
首先,您可以使用最小的数据类型来增加LUT(以及原始数据)的密度。在x86上,将零或符号扩展的8位或16位数据加载到寄存器中的成本几乎与常规32位int
加载(假定都命中高速缓存)的成本相同,而8位或16位存储区也和32位存储区一样便宜。
由于您的数据大小超过了L1 d缓存大小(对于所有最新的Intel设计,均为32kiB),并且您以分散模式访问它,因此可以通过减少缓存大小获得很多。 (有关x86性能的更多信息,请参见x86标签Wiki,尤其是Agner Fog的资料)。
由于a
在每个平面上的条目数少于65536,因此bin计数永远不会溢出16位计数器,因此bins
也可以是uint16_t
。
您的copy()
没有任何意义。为什么要复制到b[32768]
而不是让内部循环使用指向当前LUT的指针?您以只读方式使用它。您仍然要复制的唯一原因是,如果您无法将产生不同LUT的代码更改为首先生成int
或uin8_t
,则将其从int8_t
复制到uint8_t
。
这个版本利用了这些想法和一些直方图技巧,并编译为看起来不错的asm(Godbolt compiler explorer: gcc6.2 -O3 -march=haswell
(AVX2)):
// untested
//#include <algorithm>
#include <stdint.h>
const int PLANES = 1000;
void use_bins(uint16_t bins[PLANES][32]); // pass the result to an extern function so it doesn't optimize away
// 65536 or higher triggers the static_assert
alignas(64) static uint16_t a[PLANES][1000]; // static/global, I guess?
void lut_and_histogram(uint8_t __restrict__ lut[32768])
{
alignas(16) uint16_t bins[PLANES][32]; // don't zero the whole thing up front: that would evict more data from cache than necessary
// Better would be zeroing the relevant plane of each bin right before using.
// you pay the rep stosq startup overhead more times, though.
for (int i = 0; i < PLANES;i++) {
alignas(16) uint16_t tmpbins[4][32] = {0};
constexpr int a_elems = sizeof(a[0])/sizeof(uint16_t);
static_assert(a_elems > 1, "someone changed a[] into a* and forgot to update this code");
static_assert(a_elems <= UINT16_MAX, "bins could overflow");
const uint16_t *ai = a[i];
for (int j = 0 ; j<a_elems ; j+=4) { //hashing a[i] to 32 bins.
// Unrolling to separate bin arrays reduces serial dependencies
// to avoid bottlenecks when the same bin is used repeatedly.
// This has to be balanced against using too much L1 cache for the bins.
// TODO: load a vector of data from ai[j] and unpack it with pextrw.
// even just loading a uint64_t and unpacking it to 4 uint16_t would help.
tmpbins[0][ lut[ai[j+0]] ]++;
tmpbins[1][ lut[ai[j+1]] ]++;
tmpbins[2][ lut[ai[j+2]] ]++;
tmpbins[3][ lut[ai[j+3]] ]++;
static_assert(a_elems % 4 == 0, "unroll factor doesn't divide a element count");
}
// TODO: do multiple a[i] in parallel instead of slicing up a single run.
for (int k = 0 ; k<32 ; k++) {
// gcc does auto-vectorize this with a short fully-unrolled VMOVDQA / VPADDW x3
bins[i][k] = tmpbins[0][k] + tmpbins[1][k] +
tmpbins[2][k] + tmpbins[3][k];
}
}
// do something with bins. An extern function stops it from optimizing away.
use_bins(bins);
}
.L2:
movzx ecx, WORD PTR [rdx]
add rdx, 8 # pointer increment over ai[]
movzx ecx, BYTE PTR [rsi+rcx]
add WORD PTR [rbp-64272+rcx*2], 1 # memory-destination increment of a histogram element
movzx ecx, WORD PTR [rdx-6]
movzx ecx, BYTE PTR [rsi+rcx]
add WORD PTR [rbp-64208+rcx*2], 1
... repeated twice more
bins[i][k] = sum(tmpbins[0..3][k])
上进行
k
循环。
bins[i..i+unroll_factor][0..31]
归零,而不是在循环外将整个事物归零。这样,当您启动时,所有垃圾箱在L1缓存中都会很热,并且这项工作可能与内部循环中比较繁重的工作重叠。
a
加载时会有更多的缓存丢失。 (为此也要使用 vector 加载,并在加载后将它们切成薄片)。
a
值的 vector ,并使用pextrb提取到整数寄存器。 (在您的代码中,您将使用 pextrw
/ _mm_extract_epi16
)。 在所有加载/存储操作发生的情况下,进行 vector 加载并使用ALU ops进行解压缩很有意义。如果L1命中率很高,则内存uop吞吐量可能是瓶颈,而不是内存/缓存延迟。 vpgatherdd
( _mm_i32gather_epi32
),但实现效率不高。希望Skylake避免在元素之间存在重叠时多次击中同一条缓存行)。
uint16_t
数组(比例因子= 2)进行收集。这意味着您会在每个32位 vector 元素的上半部分得到垃圾,而不是0,但这没关系。高速缓存行拆分并不理想,因为我们可能在高速缓存吞吐量方面遇到瓶颈。
pextrw
提取了有用的16位。 (并使用标量代码执行过程的直方图部分)。
get_conflict_free_subset()
(
__m512i _mm512_conflict_epi32 (__m512i a)
)(它与之冲突的所有先前元素的每个元素返回一个位图)来实现
vpconflictd
。正如@Mysticial指出的那样,简单的实现要比冲突检测指令仅产生掩码寄存器结果而不是另一个 vector 要简单。
_mm512_lzcnt_epi32
的结果上使用
vplzcntd
(
vpconflictd
)是有用的,因为它也是AVX512CD的一部分。
vpbroadcastmw2d
将掩码寄存器广播到结果的所有32位元素,因此您可以将mask-register值与
vpconflictd
中每个元素中的位图对齐。 (并且AVX512F中的元素之间已经存在比较,按位和其他操作)。
VPTESTNM{D,Q}
(来自AVX512F)以及冲突检测指令。它从
DEST[j] = (SRC1[i+31:i] BITWISE AND SRC2[i+31:i] == 0)? 1 : 0
生成一个掩码。即将AND元素放在一起,如果不相交,则将该元素的 mask 结果设置为1。
关于c++ - 如何加快LUT查找的直方图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39266476/
我需要将 LUT 从 Android 应用程序传递到 fragment 着色器以进行颜色校正。我发现了一些将 LUT 作为位图传递的示例 GLES20.glBindTexture(GLES20.GL_
import numpy as np, itertools x1 = np.linspace(0.1, 3.5, 3) x2 = np.arange(5, 24, 3) x3 = np.arange(
假设我有 8 个表,每张表有 16 个值: uint32_t lut[8][16]; 我想用值填充这些表,以便组合(add、eor 等等)八个表中每个表中的一个条目将产生一个唯一的 32 位值 - 与
目前我计算日志如下: #define MAXLOG 1001 double myloglut[MAXLOG]; void MyLogCreate() { int i; double e
我们正在尝试编写一种方法来从 LUT 的链表实现中删除具有特定键的节点。 我写的代码总结: public void delete (String k) { Node currNode = li
void LUT(InputArray src, InputArray lut, OutputArray dst, int interpolation=0 ) 根据查找表在8位数组中进行替换,并将结果
我正在生成一个 LUT,将 0-2PI 分成 512 个片段,然后找到这些值的正弦并将它们存储为 Q1.31 值。 例子: LUT[0] = 0 LUT[1] = sin((1/512) * 2*PI
我正在编写一些颜色管理代码,并且正在处理 LUT(查找表)。 我可以读取颜色配置文件 LUT 并转换我的值...但是,我该如何进行逆运算?也许,是否有一个好的算法来生成 LUT 的“逆”? 最佳答案
在我正在编写的 C++ CPU 绑定(bind)模拟中,我通过程序中的 valgrind 将瓶颈追踪到 cmath::exp。它目前占用了我 40% 以上的模拟时间。我可以将输入绑定(bind)到一个
假设我需要为 0...255 个值创建一个包含预先计算的位计数值(数字中 1 位的计数)的 LUT: int CB_LUT[256] = {0, 1, 1, 2, ... 7, 8}; 如果我不想使用
我的问题与这些术语之间的区别和关系有关: LUT 逻辑单元 逻辑元件(LE) 系统门 我知道这在很大程度上取决于 FPGA 生产商,但例如 FPGA 供应商将其产品之一描述为:具有 100.000 S
我有 500 个帧,我将每个帧的长度存储在数组中,因为帧按升序排列。 const char header_length = {23,34, 45, 12, 23,56,......,2,4}; 这里帧
我需要对图像中的所有像素执行幂指数运算。这是一个非常繁重的过程。指数是常量( float ),底数是 uint32_t(乘以 2 uint16_t 的结果)我正在尝试弄清楚我是否可以编写一个 LUT,
我目前正致力于在 C 语言中建立一个框架,以便在多个微 Controller 之间使用。该框架必须承载所有设备特定代码,因此应用程序仅包含外设的抽象用法(如 SerialPort_Read、write
我的程序中需要一个查找表来描述不同类型的大小。现在我明白了: typedef struct{ APP_InterfaceType_t Type; //This is just an enu
我有一些代码可以创建一个看起来大致像这样的 HSV 掩码(取自 this Japanese-language page ): void colorExtraction(const cv::gpu::G
需要对图像的颜色 channel 应用一些快速转换。 1)我已经在列表中存储了相应的输出值: ListaVred = [0]*255 for i in range(0,255): ListaV
对于我的工作,我需要将 JPG 中的伪彩色 RGB 值替换为灰度以进行处理。 “颜色”图像具有特定范围的 RGB 颜色(20 或 255,取决于来源)需要链接到灰度值以便对输出图像进行一些测量。使用原
我正在尝试编写一个快速的 3D lut 查找函数并注意到大多数 lut 是 33x33x33 或 17x17x17。 为什么是 33 或 17?用 32 或 16 代替数学不是更快吗?所以你可以做一些
我是图像处理的新手。 我想使用 JavaScript 对使用 LUT(查找表)或相应的查找 PNG 的图像应用效果,如下所示: 我在谷歌上搜索了很多,但找不到一篇文章或任何资源来描述使用 LUT 进行
我是一名优秀的程序员,十分优秀!