这本书说如下:
对于 Knights Landing,当数据起始地址位于 64 字节边界时,内存移动是最佳的。
Q1. 有没有办法在 C++ 代码中动态查询处理器,以了解n当前运行应用程序的处理器的最佳字节边界是什么?这样,代码就可以移植了。
书中进一步指出:
作为程序员,我们最终有两项工作:(1)对齐我们的数据;(2)确保编译器知道它是对齐的。
(假设对于下面的问题,我们知道处理器的最佳数据是从 64 字节边界开始。)
这个“数据”到底是什么?
假设我有一堂课:
class Class1_{
private:
int a;//4 bytes
double b;//8 bytes
std::vector<int> potentially_longish_vector_int;
std::vector<double> potentially_longish_vector_double;
double * potentially_longish_heap_array_double;
public:
//--stuff---//
double * return_heap_array_address() {return potentially_longish_heap_array_double;}
}
Run Code Online (Sandbox Code Playgroud)
假设我还有原型化的函数:
void func1(Class1_& obj_class1);
void func2(double* array);
Run Code Online (Sandbox Code Playgroud)
也就是说,通过引用func1接收一个对象,并调用为Class1_func2func2(obj_class1.return_heap_array_address());
为了与数据应该适当边界对齐的建议保持一致,obj_class1它本身应该是 64 字节边界对齐以实现 的有效运行func1()吗?应该potentially_longish_heap_array_double对齐 64 字节边界才能有效运行吗func2()?
对于作为 STL 容器的类的其他数据成员的对齐,此处的线程建议如何完成所需的对齐。
Q2。那么,对象本身以及其中的所有数据成员是否需要适当对齐?
c++ simd vectorization memory-alignment compiler-optimization
我正在做一些事情,我想每秒多次将相同的 2x2short值矩阵与不同的二维值向量相乘,在这种情况下性能很重要。short现在,我只是以幼稚的方式进行并写出矩阵乘法。我查阅了C#的SIMD功能,发现没有办法制作这种类型的2x2矩阵。Vector<T>所以我尝试使用的结构来做到这一点System.Numerics.Vectors。不过,构造函数预计至少有 4 个元素进入向量。我可以解决它并使其与 4 维向量一起工作,但我想知道是否有一种方法可以更轻松地完成我想做的事情:将 2x2 矩阵与 2 维向量相乘成一个新的 2 维向量与SIMD。
我编写了一些用于处理单精度浮点计算 SIMD 内在函数的优化。
有时,双精度指令比任何单精度指令pd更容易满足我的要求。ps
示例1:
我有指针float prt * ,它指向浮点数块: f0 f1 f2 f3 等。
我想用 [ f0, f1, f0, f1, f0, f1, f0, f1 ] 加载 __m256 值。我没有找到__m256数据类型的 64 位广播。我可以_mm256_broadcast_sd在花车上使用吗?
float* ptr = ...; // pointer to some memory chunk aligned to 4 bytes
__m256 vat = _mm256_castpd_ps( _mm256_broadcast_sd( ( double* )ptr ) );
Run Code Online (Sandbox Code Playgroud)
示例2:
我有 __m256 值 [f0, f1, f2, f3, f4, f5, f6, f7]。我可以使用像 _mm256_srl_epi32 这样的移位指令,它以 __m256i 值作为参数来使用我的 __m256 值进行操作吗? …
我正在尝试hello neon提供的示例,android/ndk-samples并在两台设备上测试了 fir 过滤器演示,一台设备支持ABI armeabi-v7a,另一台设备支持arm64-v8aABI。
默认情况下,JNI 代码会失败arm64-v8a,但这可以通过一些调整来解决。现在,当我最终在两个设备上运行比较代码(具有不同规格)时,我得到以下结果
armeabi-v7a设备 - 四核,32 位C Version: 182.47 ms
Neon Version: 69.782 ms (2.62x faster)
Run Code Online (Sandbox Code Playgroud)
arm64-v8a设备 - 八核,64 位C Version: 10.189 ms
Neon Version: 19.4836 ms (0.52295x faster)
Run Code Online (Sandbox Code Playgroud)
为什么这个霓虹灯版本的速度会变慢arm64-v8a?
(我对 NEON 和 SIMD 相当陌生)
链接到内部代码 - cpp/helloneon-intrinsics.c
有vrecpeq_f32ARM NEON Intrinsic。
官方解释vrecpeq_f32:https://developer.arm.com/architectures/instruction-sets/intrinsics/#f :@navigationhierarchiessimdisa=[Neon]&q=vrecpeq_f32 。
浮点倒数估计。该指令查找源 SIMD&FP 寄存器中每个向量元素的近似倒数估计,将结果放入向量中,并将该向量写入目标 SIMD&FP 寄存器。
然而,它对我来说仍然不准确。只是想知道我们是否可以用 C/C++ 编写一个参考实现来保持与 完全相同的结果vrecpeq_f32?
我尝试打电话 vrecpeq_f32并得到结果:
float32x4_t v1 = {1, 2, 3, 4};
float32x4_t v_out = vrecpeq_f32(v1);//0.99805, 0.49902, 0.33301, 0.24951
Run Code Online (Sandbox Code Playgroud)
很好奇为什么 1 的倒数是 0.99805 而不是 1.0。
PS 我对如何使用 NEON 内在函数和一些技巧来获得更好的精度倒数结果不感兴趣,例如一次或多次牛顿-拉夫森迭代。
我一直在比较 Intrinsics 向量缩减、朴素向量缩减和使用 openmp 编译指示的向量缩减的运行时间。然而,我发现这些场景的结果是不同的。代码如下 - (内在向量归约取自 - Fastest way to dohorizontal SSE vector sum(或其他归约))
#include <iostream>
#include <chrono>
#include <vector>
#include <numeric>
#include <algorithm>
#include <immintrin.h>
inline float hsum_ps_sse3(__m128 v) {
__m128 shuf = _mm_movehdup_ps(v); // broadcast elements 3,1 to 2,0
__m128 sums = _mm_add_ps(v, shuf);
shuf = _mm_movehl_ps(shuf, sums); // high half -> low half
sums = _mm_add_ss(sums, shuf);
return _mm_cvtss_f32(sums);
}
float hsum256_ps_avx(__m256 v) {
__m128 vlow = _mm256_castps256_ps128(v);
__m128 vhigh = _mm256_extractf128_ps(v, 1); // high …Run Code Online (Sandbox Code Playgroud) __m256i我正在寻找使用 AVX 将压缩的 32 位整数除以二(也称为右移一位)的最快方法。我无法访问 AVX2。据我所知,我的选择是:
如果我需要使用 SSE2,我会欣赏最好的 SSE2 实现。如果是 2),我想知道要使用的内在函数,以及是否有更优化的实现来专门除以 2。谢谢!
ALIGNTO(16) uint8_t noise_frame_flags[16] = { 0 };
// Code detects noise and sets noise_frame_flags omitted
__m128i xmm0 = _mm_load_si128((__m128i*)noise_frame_flags);
bool isNoiseToCancel = _mm_extract_epi64(xmm0, 0) | _mm_extract_epi64(xmm0, 1);
if (isNoiseToCancel)
cancelNoises(audiobuffer, nAudioChannels, audio_samples, noise_frame_flags);
Run Code Online (Sandbox Code Playgroud)
这是我在 Linux 上的 AV Capture 工具的代码片段。这里的noise_frame_flags是16通道音频的标志数组。对于每个通道,相应的字节可以是 0 或 1。1 表示该通道有一些噪声需要消除。例如,如果noise_frame_flags[0] == 1,则意味着设置了第一个通道噪声标志(通过省略的代码)。
即使设置了一个“标志”,我也需要调用cancelNoises. 这段代码在这方面似乎工作得很好。正如您所看到的,我曾经_mm_load_si128加载正确对齐的整个标志数组,然后加载两个_mm_extract_epi64来提取“标志”。我的问题是有更好的方法来做到这一点(也许使用流行计数)?
注意:ALIGNTO(16)是一个宏扩展以纠正 GCC 等效项,但外观更好。
对于 x86-64,有许多指令集可以加速代码执行。以下是 gcc wiki https://gcc.gnu.org/wiki/FunctionMultiVersioning的列表:
-O2?为了简单起见,我们只说问题是关于 gcc 版本 12(最新的主要版本)。但我想知道我需要做什么 gcc 命令开关/选项,以便我可以看到我的 gcc 版本的功能。
我认为 gcc 选择了“可移植”的东西,所以这可能意味着速度很慢。但这只是我的假设......我想知道这是否意味着像SSE4.2或没有?
是否可以访问mmx寄存器中的单个字节,如数组?我有这个代码:
movq mm1,vector1
movq mm2,vector2
psubw mm1,mm2
Run Code Online (Sandbox Code Playgroud)
我想把mm1 [1],mm1 [2],mm1 [3] ....放到c ++变量中,比如:
int a,b=0;
mov a,mm1[1]
mov b,mm1[2]
Run Code Online (Sandbox Code Playgroud)
谢谢.