当前位置: 首页 > 知识库问答 >
问题:

如何使用neon Intrinsic优化直方图统计?

佴阳曦
2023-03-14

我想优化直方图统计代码与霓虹灯内部。但是我没有成功。这里是c代码:

#define NUM (7*1024*1024)
uint8 src_data[NUM];
uint32 histogram_result[256] = {0};
for (int i = 0; i < NUM; i++)
{
    histogram_result[src_data[i]]++;
}

直方图统计更像是串行处理。使用neon intrinsics很难进行优化。有人知道如何优化吗?提前谢谢。

共有1个答案

欧阳正德
2023-03-14

您不能直接对存储进行矢量化,但可以通过管道对其进行矢量化,并且可以在32位平台上对地址计算进行矢量化(在64位平台上的矢量化程度较低)。

你要做的第一件事,实际上并不需要NEON受益,就是展开直方图数组,这样你就可以一次拥有更多的数据

#define NUM (7*1024*1024)
uint8 src_data[NUM];
uint32 histogram_result[256][4] = {{0}};
for (int i = 0; i < NUM; i += 4)
{
    uint32_t *p0 = &histogram_result[src_data[i + 0]][0];
    uint32_t *p1 = &histogram_result[src_data[i + 1]][1];
    uint32_t *p2 = &histogram_result[src_data[i + 2]][2];
    uint32_t *p3 = &histogram_result[src_data[i + 3]][3];
    uint32_t c0 = *p0;
    uint32_t c1 = *p1;
    uint32_t c2 = *p2;
    uint32_t c3 = *p3;
    *p0 = c0 + 1;
    *p1 = c1 + 1;
    *p2 = c2 + 1;
    *p3 = c3 + 1;
}

for (int i = 0; i < 256; i++)
{
    packed_result[i] = histogram_result[i][0]
                     + histogram_result[i][1]
                     + histogram_result[i][2]
                     + histogram_result[i][3];
}

请注意,p0p3永远不能指向同一地址,因此对它们的读写重新排序就可以了。

由此,您可以使用intrinsic将p0的计算矢量化为p3,并可以矢量化最终循环。

首先测试它(因为我没有!)。然后,您可以尝试将数组构造为result[4][256],而不是result[256][4],或者使用更小或更大的展开因子。

将某些霓虹灯内在特性应用于此:

uint32 histogram_result[256 * 4] = {0};
static const uint16_t offsets[] = { 0x000, 0x001, 0x002, 0x003,
                                    0x000, 0x001, 0x002, 0x003 };
uint16x8_t voffs = vld1q_u16(offsets);
for (int i = 0; i < NUM; i += 8) {
    uint8x8_t p = vld1_u8(&src_data[i]);
    uint16x8_t p16 = vshll_n_u8(p, 16);
    p16 = vaddq_u16(p16, voffs);
    uint32_t c0 = histogram_result[vget_lane_u16(p16, 0)];
    uint32_t c1 = histogram_result[vget_lane_u16(p16, 1)];
    uint32_t c2 = histogram_result[vget_lane_u16(p16, 2)];
    uint32_t c3 = histogram_result[vget_lane_u16(p16, 3)];
    histogram_result[vget_lane_u16(p16, 0)] = c0 + 1;
    c0 = histogram_result[vget_lane_u16(p16, 4)];
    histogram_result[vget_lane_u16(p16, 1)] = c1 + 1;
    c1 = histogram_result[vget_lane_u16(p16, 5)];
    histogram_result[vget_lane_u16(p16, 2)] = c2 + 1;
    c2 = histogram_result[vget_lane_u16(p16, 6)];
    histogram_result[vget_lane_u16(p16, 3)] = c3 + 1;
    c3 = histogram_result[vget_lane_u16(p16, 7)];
    histogram_result[vget_lane_u16(p16, 4)] = c0 + 1;
    histogram_result[vget_lane_u16(p16, 5)] = c1 + 1;
    histogram_result[vget_lane_u16(p16, 6)] = c2 + 1;
    histogram_result[vget_lane_u16(p16, 7)] = c3 + 1;
}

如果直方图数组展开为x8而不是x4,您可能希望使用八个标量累加器而不是四个,但您必须记住,这意味着八个计数寄存器和八个地址寄存器,这比32位ARM的寄存器多(因为您不能使用SP和PC)。

不幸的是,由于地址计算掌握在NEON Intrinsic手中,我认为编译器无法安全地推理它如何能够对读写进行重新排序,因此您必须显式地对它们进行重新排序,并希望以最好的方式进行。

 类似资料:
  • 我们的java流媒体服务器正在生产中运行,它需要约10GB的RAM才能运行,所以我们安装了32GB。内存会逐渐增加,直到达到限制并弹出内存不足异常。 由于直方图和内存转储数字与系统报告的内存使用量不匹配,我很难准确地指出随着时间的推移,哪些对象正在累积,也就是说,java进程占用的内存略多于最大20GB(因此内存不足异常是合理的),但直方图和内存转储显示总共使用了6.4GB。 如何在直方图中未显示

  • 我想用python绘制一个非常简单的直方图。这是我的代码: 这就是结果 我怎样才能把这些条放在整数的地方呢?为什么我的图表也显示浮点数?

  • 目标 我们将学习直方图均衡的概念,并用它来改善我们的图片对比度。 理论基础 考虑像素值仅限于某个特定值范围的图像。例如,较亮的图像将所有像素限制在较高的值。但是一张好的图像将会具有来自图像所有区域的像素。所以你需要将这个直方图拉伸到两端,用简单的话来说,这就是直方图均衡化所能做到的。这通常会改善图像的对比度。 我建议你阅读关于直方图均衡化的维基百科页面,了解更多细节。它解释的很好而且有相当好的例子

  • 问题内容: 我在netbeans平台上制作了App。我想绘制直方图。我有红色,绿色和蓝色的图像像素。因此,请任何人对我提出建议,如何使用该像素值绘制直方图?我的代码在下面,其中我使用图像的红色,绿色和蓝色像素值。 问题答案:

  • numpy.histogram()函数将输入数组和作为两个参数。 bin数组中的连续元素用作每个bin的边界。 Matplotlib 可以将直方图的数字表示转换为图形。 pyplot子模块的plt()函数将包含数据和数组的数组作为参数,并转换为直方图。

  • 我正在尝试使用 marplot.lib 库在 Python 中绘制直方图;但是,我一直收到此错误:“属性错误:箱必须单调增加。 这是我目前的代码: 传入的参数是信息。“信息”是一个元组列表,可能如下所示: [(4, 0.7984031936127745), (5, 0.5988023952095809), (5, 0.8739076154806492), (5, 0.736454497632824