我正在尝试使用SIMD指令(_mm256_add_pd、store、load等)优化C中的2D矩阵加法。然而,我并没有看到一个大的加速。使用一些计时代码,我看到的加速范围是.8x-1.5倍的朴素解决方案)。我想知道这是否是典型的?我想这可能是一个内存瓶颈,因为在这种情况下,计算似乎很少。我相信这应该给我的速度提高大约4倍,因为我正在做4次加法,所以我不完全确定瓶颈是什么。
我做了一些代码来演示我正在做的事情(测试并行+SIMD与仅SIMD):
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include <time.h>
#include <omp.h>
#include <string.h>
#if defined(_MSC_VER)
#include <intrin.h>
#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
#include <immintrin.h>
#include <x86intrin.h>
#endif
void add_matrix_naive (double **result, double **mat1, double **mat2, int rows, int cols) {
int simdCols = cols / 4 * 4;
if(simdCols > 0){
for(unsigned int i = 0; i < rows; i++){
for(unsigned int j = 0; j < simdCols; j += 4){
_mm256_storeu_pd(result[i] + j, _mm256_add_pd(
_mm256_loadu_pd(mat1[i] + j)
, _mm256_loadu_pd(mat2[i] + j)));
}
}
}
//Handle extra columns
if(simdCols < cols){
for(unsigned int i = 0; i < rows; i++){
for(unsigned int j = simdCols; j < cols; j++){
result[i][j] = mat1[i][j] + mat2[i][j];
}
}
}
}
void add_matrix(double **result, double **mat1, double **mat2, int rows, int cols) {
int simdCols = cols / 4 * 4;
#pragma omp parallel if (rows*cols >= 2000)
{
if(simdCols > 0){
#pragma omp for collapse(2)
for(unsigned int i = 0; i < rows; i++){
for(unsigned int j = 0; j < simdCols; j += 4){
_mm256_storeu_pd(result[i] + j, _mm256_add_pd(
_mm256_loadu_pd(mat1[i] + j)
, _mm256_loadu_pd(mat2[i] + j)));
}
}
}
//Handle extra columns
if(simdCols < cols){
#pragma omp for collapse(2)
for(unsigned int i = 0; i < rows; i++){
for(unsigned int j = simdCols; j < cols; j++){
result[i][j] = mat1[i][j] + mat2[i][j];
}
}
}
}
}
int main()
{
omp_set_num_threads(8);
//Allocate Matrices
int rows = 200;
int cols = 200;
double **matrix_a = malloc(rows * sizeof(double *) + rows*cols*sizeof(double));
double * dataStart = (double *) matrix_a + rows; //Offset row pointers
for(unsigned int i = 0; i < rows; i++){
matrix_a[i] = dataStart + i * cols;
memset(matrix_a[i], 0, sizeof(double) * cols);
}
double **matrix_b = malloc(rows * sizeof(double *) + rows*cols*sizeof(double));
dataStart = (double *) matrix_b + rows; //Offset row pointers
for(unsigned int i = 0; i < rows; i++){
matrix_b[i] = dataStart + i * cols;
memset(matrix_b[i], 0, sizeof(double) * cols);
}
double **result = malloc(rows * sizeof(double *) + rows*cols*sizeof(double));
dataStart = (double *) result + rows; //Offset row pointers
for(unsigned int i = 0; i < rows; i++){
result[i] = dataStart + i * cols;
memset(result[i], 0, sizeof(double) * cols);
}
//Assign random values to matrices.
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
matrix_a[i][j] = rand();
matrix_b[i][j] = rand();
}
}
int LOOP_COUNT = 4;
double prevTime = omp_get_wtime();
for(int i = 0; i < LOOP_COUNT; i++){
add_matrix(result, matrix_a, matrix_b, rows, cols);
}
double endTime = omp_get_wtime();
double firstTime = (endTime - prevTime)/LOOP_COUNT;
printf("Took %f Seconds\n", firstTime);
//Assign random values to matrices.
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
matrix_a[i][j] = rand();
matrix_b[i][j] = rand();
}
}
prevTime = omp_get_wtime();
for(int i = 0; i < LOOP_COUNT; i++){
add_matrix_naive(result, matrix_a, matrix_b, rows, cols);
}
endTime = omp_get_wtime();
double secondTime = (endTime - prevTime)/LOOP_COUNT;
printf("Took %f Seconds\n", secondTime);
printf("Naive Time: %f Faster\n", firstTime/secondTime);
}
我注意到,结果似乎很大程度上取决于loop_count。当循环数较高时,并行/SIMD版本做得相当好,但当循环数较低时,朴素的解决方案往往做得更好。
CPU的计算速度比它们访问内存的速度快得多。
加双打是非常快的。你的核心很可能是内存瓶颈。
还有更多。
但最重要的是,你的基准测试是完全错误的。
>
要比较算法的不同实现,必须编译2个不同的程序。当您在一个程序中运行这两种实现时,会发生许多有趣的事情:缓存层次结构开始出现,CPU有另一个专用缓存用于解码指令,现代CPU在热节流方面速度极快,等等。
编译器并不愚蠢。当他们意识到你在不使用结果的情况下计算了一些东西时,他们可以丢弃代码。当他们意识到你在不改变输入数据的情况下多次计算某件事时,他们就可以消除冗余代码,只计算一次。
对于 big 机器,比如 128 核,512GB 这种机器,一次性跑几百个相同 docker 容器 我发现开的越多,速度增长的越慢 cpu 是确实利用起来了,都是 100% RAM 容量只用了 30%,也没有发生 swap 但是速度就是起不来 我怀疑是内存带宽之类的跑满了?有什么工具可以看「内存带宽」的使用率? htop、glances 这类工具,只能看「内存容量」维度,看不到「内存带宽」维度
本文向大家介绍简述HBase的瓶颈相关面试题,主要包含被问及简述HBase的瓶颈时的应答技巧和注意事项,需要的朋友参考一下 解答: HBase的瓶颈就是硬盘传输速度。HBase的操作,它可以往数据里面insert,也可以update一些数据,但update的实际上也是insert,只是插入一个新的时间戳的一行。Delete数据,也是insert,只是insert一行带有delete标记的一行。Hb
它使用关联reduce函数合并每个键的值,但将结果作为映射立即返回给主程序。在将结果发送到reducer之前,这也将在每个映射器上执行本地合并,类似于MapReduce中的“合并器”。 除了ReduceByKeyLocal将结果作为映射返回给主程序之外,我看不出两者之间有多大区别。
有没有我们可以用来进行指令集检测的宏? 我知道我们有运行时程序: 但我们是否已经定义了这方面的符号,例如。 如果没有,我们可以创建一个或我们有一个解决办法吗? 在玩反编译器的时候,我发现了一个奇怪的“递归”。但我想ILSpy漏了。 此外,当我查看一个简单的代码时,我注意到以下内容: ASM 正如您所看到的,它不知怎么弄明白了Avx是受支持的,并且不包括分支。这是正常和明确的行为吗?
在C/C中,可以对SIMD(如AVX和AVX2)指令使用内部函数。有没有办法在Rust中使用SIMD?
主要内容:对称矩阵,上(下)三角矩阵,稀疏矩阵,矩阵压缩存储的 3 种方式数据结构中,提供针对某些特殊矩阵的压缩存储结构。 这里所说的特殊矩阵,主要分为以下两类: 含有大量相同数据元素的矩阵,比如对称矩阵; 含有大量 0 元素的矩阵,比如稀疏矩阵、上(下)三角矩阵; 针对以上两类矩阵,数据结构的压缩存储思想是:矩阵中的相同数据元素(包括元素 0)只存储一个。 对称矩阵 图 1 对称矩阵示意图 图 1 的矩阵中,数据元素沿主对角线对应相等,这类矩阵称为 对称矩阵。 矩阵中