我有一个矩阵(相对较大),我需要转置.例如假设我的矩阵是
a b c d e f
g h i j k l
m n o p q r
Run Code Online (Sandbox Code Playgroud)
我希望结果如下:
a g m
b h n
c I o
d j p
e k q
f l r
Run Code Online (Sandbox Code Playgroud)
最快的方法是什么?
我目前正在编写一些针对英特尔即将推出的AVX-512 SIMD指令的代码,该指令支持512位操作.
现在假设有一个由16个SIMD寄存器表示的矩阵,每个寄存器包含16个32位整数(对应一行),如何用纯SIMD指令转置矩阵?
已经有解决方案分别用SSE和AVX2转置4x4或8x8矩阵.但我无法弄清楚如何使用AVX-512将其扩展到16x16.
有任何想法吗?
(相关:如何在Sandy Bridge上的一系列int中快速将位计数到单独的bin中?是对此的早期复制,带有一些不同的答案。编者注:这里的答案可能更好。
同样,是类似问题的AVX2版本,整行位的许多bin比一个宽得多uint64_t
:改进列填充计数算法)
我正在C中的一个项目中,我需要经历数千万个掩码(ulong类型(64位)),并target
基于一个简单规则更新64个短整数(uint16)的数组(称为):
// for any given mask, do the following loop
for (i = 0; i < 64; i++) {
if (mask & (1ull << i)) {
target[i]++
}
}
Run Code Online (Sandbox Code Playgroud)
问题是我需要在数以百万计的蒙版上执行上述循环,并且我需要在不到一秒钟的时间内完成。想知道是否有任何方法可以加快它的速度,例如使用某种表示上述循环的特殊汇编指令。
目前,我在ubuntu 14.04(i7-2670QM,支持AVX,而不是AVX2)上使用gcc 4.8.4来编译和运行以下代码,大约需要2秒钟。很想让它在200ms以下运行。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/stat.h>
double getTS() {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + tv.tv_usec / 1000000.0;
}
unsigned int target[64];
int main(int argc, char *argv[]) {
int i, …
Run Code Online (Sandbox Code Playgroud) 我std::vector<std::vector<double>>
正在尝试尽快将其转换为单个连续向量。我的向量的形状大致为4000 x 50
。
问题是,有时我的输出向量需要以列为主的连续顺序(仅将2d输入向量的内部向量连接起来),有时我的输出向量需要以行为主的连续顺序,实际上需要转置。
我发现,朴素的for循环对于转换为以列为主的向量非常快:
auto to_dense_column_major_naive(std::vector<std::vector<double>> const & vec)
-> std::vector<double>
{
auto n_col = vec.size();
auto n_row = vec[0].size();
std::vector<double> out_vec(n_col * n_row);
for (size_t i = 0; i < n_col; ++i)
for (size_t j = 0; j < n_row; ++j)
out_vec[i * n_row + j] = vec[i][j];
return out_vec;
}
Run Code Online (Sandbox Code Playgroud)
但是显然,由于所有的高速缓存未命中,因此类似的方法对于逐行转换非常慢。因此,对于逐行转换,我认为提高缓存局部性的阻止策略可能是我最好的选择:
auto to_dense_row_major_blocking(std::vector<std::vector<double>> const & vec)
-> std::vector<double>
{
auto n_col = vec.size();
auto n_row = vec[0].size();
std::vector<double> out_vec(n_col * n_row);
size_t block_side …
Run Code Online (Sandbox Code Playgroud) 我需要一个快速的内存转置算法,用于C/C++中的高斯卷积函数.我现在做的是
convolute_1D
transpose
convolute_1D
transpose
Run Code Online (Sandbox Code Playgroud)
事实证明,使用这种方法,滤波器的大小必须很大(或大于我的预期),或者转置需要比卷积更长的时间(例如,对于1920x1080矩阵,卷积与转置的时间相同,滤波器大小为35 ).我正在使用的当前转置算法使用循环阻塞/平铺以及SSE和OpenMP.我尝试过使用AVX的版本,但速度并不快.关于如何加快速度的任何建议?
inline void transpose4x4_SSE(float *A, float *B, const int lda, const int ldb) {
__m128 row1 = _mm_load_ps(&A[0*lda]);
__m128 row2 = _mm_load_ps(&A[1*lda]);
__m128 row3 = _mm_load_ps(&A[2*lda]);
__m128 row4 = _mm_load_ps(&A[3*lda]);
_MM_TRANSPOSE4_PS(row1, row2, row3, row4);
_mm_store_ps(&B[0*ldb], row1);
_mm_store_ps(&B[1*ldb], row2);
_mm_store_ps(&B[2*ldb], row3);
_mm_store_ps(&B[3*ldb], row4);
}
//block_size = 16 works best
inline void transpose_block_SSE4x4(float *A, float *B, const int n, const int m, const int lda, const int ldb ,const int block_size) {
#pragma omp parallel for …
Run Code Online (Sandbox Code Playgroud) 我发现这个职位,说明如何进行转一个8x8矩阵的字节24点的操作,和几个卷轴后有代码实现转置.但是,这种方法没有利用我们可以阻止 8x8转置为4个4x4转置的事实,并且每个转换只能在一个shuffle指令中完成(这篇文章是参考文献).所以我推出了这个解决方案:
__m128i transpose4x4mask = _mm_set_epi8(15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0);
__m128i shuffle8x8Mask = _mm_setr_epi8(0, 1, 2, 3, 8, 9, 10, 11, 4, 5, 6, 7, 12, 13, 14, 15);
void TransposeBlock8x8(uint8_t *src, uint8_t *dst, int srcStride, int dstStride) {
__m128i load0 = _mm_set_epi64x(*(uint64_t*)(src + 1 * srcStride), *(uint64_t*)(src + 0 * srcStride));
__m128i load1 = _mm_set_epi64x(*(uint64_t*)(src + 3 * srcStride), *(uint64_t*)(src + …
Run Code Online (Sandbox Code Playgroud) (我是SSE/asm的新手,如果这显而易见或多余则道歉)
是否有更好的方法来转换包含16位值的8个SSE寄存器,而不是执行24个unpck [lh] ps和8/16 + shuffle以及使用8个额外的寄存器?(注意最多使用SSSE 3指令,Intel Merom,又称SSE4缺少BLEND*.)
假设你有寄存器v [0-7]并使用t0-t7作为辅助寄存器.在伪内在函数代码中:
/* Phase 1: process lower parts of the registers */
/* Level 1: work first part of the vectors */
/* v[0] A0 A1 A2 A3 A4 A5 A6 A7
** v[1] B0 B1 B2 B3 B4 B5 B6 B7
** v[2] C0 C1 C2 C3 C4 C5 C6 C7
** v[3] D0 D1 D2 D3 D4 D5 D6 D7
** v[4] E0 E1 E2 E3 E4 E5 E6 E7 …
Run Code Online (Sandbox Code Playgroud) 1)有没有办法使用具有以下特征的SSE3(无SSE4)有效地实现符号功能?
__m128
. __m128
以[-1.0f,0.0f,1.0f]作为其值 我尝试过这个,但它不起作用(虽然我认为它应该):
inputVal = _mm_set_ps(-0.5, 0.5, 0.0, 3.0);
comp1 = _mm_cmpgt_ps(_mm_setzero_ps(), inputVal);
comp2 = _mm_cmpgt_ps(inputVal, _mm_setzero_ps());
comp1 = _mm_castsi128_ps(_mm_castps_si128(comp1));
comp2 = _mm_castsi128_ps(_mm_castps_si128(comp2));
signVal = _mm_sub_ps(comp1, comp2);
Run Code Online (Sandbox Code Playgroud)
2)有没有办法创建"标志"功能(我不确定正确的名称).即,如果A > B
结果将是1
和0
否则.结果应该是float-point(__m128
),就像它的输入一样.
更新:Cory Nelson的回答似乎在这里有效:
__m128 greatherThanFlag = _mm_and_ps(_mm_cmpgt_ps(valA, valB), _mm_set1_ps(1.0f));
__m128 lessThanFlag = _mm_and_ps(_mm_cmplt_ps(valA, valB), _mm_set1_ps(1.0f));
Run Code Online (Sandbox Code Playgroud) 我试图找出如何转置(在AVX2内部函数中)矩形矩阵,该矩形矩阵由8行__m256i寄存器组成,每行包含32x 8位(字符)。
__m256i matrix[8]; //32x8bit integers
Run Code Online (Sandbox Code Playgroud)
转置的矩阵就像32行的8x 8位整数,但我也可以用相同的方式表示它:8行的__m256i,每行包含4行的64位。
我知道_mm256_shuffle_epi8适用于此类问题,但是我不知道如何在矩形矩阵的这种特殊情况下使用它。
我正在评估我的项目的网络+渲染工作负载。
程序连续运行一个主循环:
while (true) {
doSomething()
drawSomething()
doSomething2()
sendSomething()
}
Run Code Online (Sandbox Code Playgroud)
主循环每秒运行 60 多次。
我想查看性能故障,每个程序需要多少时间。
我担心的是,如果我打印每个程序的每个入口和出口的时间间隔,
这会导致巨大的性能开销。
我很好奇什么是衡量性能的惯用方法。
日志打印是否足够好?