AVX256加速矩阵乘法
最近打PKU的HPCGAME留下的代码,速度不是很快
const int BLOCK_SIZE = 1024;
const int BLOCK_SIZE2 = 256;
inline static void block_avx256_16x2( // 电脑不支持AVX512捏
int n,int K, //方阵大小
double* A, double* B, double* C)
{
__m256d c0000_0300, c0400_0700, c0800_1100, c1200_1500,
c0001_0301, c0401_0701, c0801_1101, c1201_1501;
__m256d a0x_3x, a4x_7x, a8x_11x, a12x_15x,
bx0, bx1;
double* c0001_0301_ptr = C + n;
c0000_0300 = _mm256_load_pd(C);
c0400_0700 = _mm256_load_pd(C + 4);
c0800_1100 = _mm256_load_pd(C + 8);
c1200_1500 = _mm256_load_pd(C + 12);
c0001_0301 = _mm256_load_pd(c0001_0301_ptr);
c0401_0701 = _mm256_load_pd(c0001_0301_ptr + 4);
c0801_1101 = _mm256_load_pd(c0001_0301_ptr + 8);
c1201_1501 = _mm256_load_pd(c0001_0301_ptr + 12);
for (int x = 0; x < K; ++x)
{
a0x_3x = _mm256_load_pd(A);
a4x_7x = _mm256_load_pd(A + 4);
a8x_11x = _mm256_load_pd(A + 8);
a12x_15x = _mm256_load_pd(A + 12);
A+= 16;
bx0 = _mm256_broadcast_sd(B++);
bx1 = _mm256_broadcast_sd(B++);
c0000_0300 = _mm256_add_pd(_mm256_mul_pd(a0x_3x, bx0), c0000_0300);
c0400_0700 = _mm256_add_pd(_mm256_mul_pd(a4x_7x, bx0), c0400_0700);
c0800_1100 = _mm256_add_pd(_mm256_mul_pd(a8x_11x, bx0), c0800_1100);
c1200_1500 = _mm256_add_pd(_mm256_mul_pd(a12x_15x, bx0), c1200_1500);
c0001_0301 = _mm256_add_pd(_mm256_mul_pd(a0x_3x, bx1), c0001_0301);
c0401_0701 = _mm256_add_pd(_mm256_mul_pd(a4x_7x, bx1), c0401_0701);
c0801_1101 = _mm256_add_pd(_mm256_mul_pd(a8x_11x, bx1), c0801_1101);
c1201_1501 = _mm256_add_pd(_mm256_mul_pd(a12x_15x, bx1), c1201_1501);
}
_mm256_storeu_pd(C, c0000_0300);
_mm256_storeu_pd(C + 4, c0400_0700);
_mm256_storeu_pd(C + 8, c0800_1100);
_mm256_storeu_pd(C + 12, c1200_1500);
_mm256_storeu_pd(c0001_0301_ptr, c0001_0301);
_mm256_storeu_pd(c0001_0301_ptr + 4, c0401_0701);
_mm256_storeu_pd(c0001_0301_ptr + 8, c0801_1101);
_mm256_storeu_pd(c0001_0301_ptr + 12, c1201_1501);
}
static inline void copy_b(int lda, const int K, double* b_src, double* b_dest) {
double* b_ptr0, * b_ptr1;
b_ptr0 = b_src;
b_ptr1 = b_ptr0 + lda;
for (int i = 0; i < K; ++i)
{
*b_dest++ = *b_ptr0++;
*b_dest++ = *b_ptr1++;
}
}
static inline void copy_a(int lda, const int K, double* a_src, double* a_dest) {
for (int i = 0; i < K; ++i)
{
*a_dest++ = *a_src;
*a_dest++ = *(a_src + 1);
*a_dest++ = *(a_src + 2);
*a_dest++ = *(a_src + 3);
*a_dest++ = *(a_src + 4);
*a_dest++ = *(a_src + 5);
*a_dest++ = *(a_src + 6);
*a_dest++ = *(a_src + 7);
*a_dest++ = *(a_src + 8);
*a_dest++ = *(a_src + 9);
*a_dest++ = *(a_src + 10);
*a_dest++ = *(a_src + 11);
*a_dest++ = *(a_src + 12);
*a_dest++ = *(a_src + 13);
*a_dest++ = *(a_src + 14);
*a_dest++ = *(a_src + 15);
a_src += lda;
}
}
static inline void do_block(int lda, int M, int N, int K, double* A, double* B, double* C)
{
double *A_block, *B_block;
A_block = (double*)_mm_malloc(M * K * sizeof(double), 64);
B_block = (double*)_mm_malloc(K * N * sizeof(double), 64);
double* a_ptr, * b_ptr, * c;
const int Nmax = N - 1;
int Mmax = M - 15;
int i = 0, j = 0, p = 0;
for (j = 0; j < Nmax; j += 2)
{
b_ptr = &B_block[j * K];
copy_b(lda, K, B + j * lda, b_ptr); // 将 B 展开
for (i = 0; i < Mmax; i += 16) {
a_ptr = &A_block[i * K];
if (j == 0) copy_a(lda, K, A + i, a_ptr); // 将 A 展开
c = C + i + j * lda;
block_avx256_16x2(lda, K, a_ptr, b_ptr, c);
}
}
_mm_free(A_block);
_mm_free(B_block);
}
void gemm(int lda, double* A, double* B, double* C)
{
#pragma omp parallel for
for (int j = 0; j < lda; j += BLOCK_SIZE) { // j i k 序 内存读写更快
for (int i = 0; i < lda; i += BLOCK_SIZE) {
for (int k = 0; k < lda; k += BLOCK_SIZE) {
// 大分块里小分块
for (int jj = j; jj < j + BLOCK_SIZE; jj += BLOCK_SIZE2)
for (int ii = i; ii < i + BLOCK_SIZE; ii += BLOCK_SIZE2)
for (int kk = k; kk < k + BLOCK_SIZE; kk += BLOCK_SIZE2)
do_block(lda, BLOCK_SIZE2, BLOCK_SIZE2, BLOCK_SIZE2, A + ii + kk * lda, B + kk + jj * lda, C + ii + jj * lda);
}
}
}
}
AVX256加速矩阵乘法的更多相关文章
- 【POJ3613】Cow Relays 离散化+倍增+矩阵乘法
题目大意:给定一个 N 个顶点,M 条边的无向图,求从起点到终点恰好经过 K 个点的最短路. 题解:设 \(d[1][i][j]\) 表示恰好经过一条边 i,j 两点的最短路,那么有 \(d[r+m] ...
- 如何使用矩阵乘法加速动态规划——以[SDOI2009]HH去散步为例
对这个题目的最初理解 开始看到这个题,觉得很水,直接写了一个最简单地动态规划,就是定义 f[i][j]为到了i节点路径长度为j的路径总数, 转移的话使用Floyd算法的思想去转移,借助这个题目也理解了 ...
- [模板][题解][Luogu1939]矩阵乘法加速递推(详解)
题目传送门 题目大意:计算数列a的第n项,其中: \[a[1] = a[2] = a[3] = 1\] \[a[i] = a[i-3] + a[i - 1]\] \[(n ≤ 2 \times 10^ ...
- BZOJ 1009 GT考试 (AC自动机 + 矩阵乘法加速dp)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1009 题意: 准考证号为\(n\)位数\(X_1X_2....X_n(0<=X_ ...
- 『公交线路 状压dp 矩阵乘法加速』
公交线路 Description 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的 ...
- c++的矩阵乘法加速trick
最近读RNNLM的源代码,发现其实现矩阵乘法时使用了一个trick,这里描述一下这个trick. 首先是正常版的矩阵乘法(其实是矩阵乘向量) void matrixXvector(float* des ...
- HDU 5607 graph(DP+矩阵乘法)
[题目链接] http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=663&pid=1002 [题意] 给定一个有向 ...
- BZOJ_1009_[HNOI2008]GT考试_KMP+矩阵乘法
BZOJ_1009_[HNOI2008]GT考试_KMP+矩阵乘法 Description 阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考 ...
- Codeforces 1106F Lunar New Year and a Recursive Sequence | BSGS/exgcd/矩阵乘法
我诈尸啦! 高三退役选手好不容易抛弃天利和金考卷打场CF,结果打得和shi一样--还因为queue太长而unrated了!一个学期不敲代码实在是忘干净了-- 没分该没分,考题还是要订正的 =v= 欢迎 ...
- [转]OpenBLAS项目与矩阵乘法优化
课程内容 OpenBLAS项目介绍 矩阵乘法优化算法 一步步调优实现 以下为公开课完整视频,共64分钟: 以下为公开课内容的文字及 PPT 整理. 雷锋网的朋友们大家好,我是张先轶,今天主要介绍一下我 ...
随机推荐
- 【LeetCode哈希表#2】两个数组的交集(Set+数组)
两个数组的交集 力扣题目链接(opens new window) 题意:给定两个数组,编写一个函数来计算它们的交集. 说明: 输出结果中的每个元素一定是唯一的. 我们可以不考虑输出结果的顺序. 思路 ...
- 【Azure 存储服务】使用PowerShell脚本创建存储账号(Storage Account)的共享访问签名(SASToken) : New-AzStorageContainerSASToken
问题描述 使用PowerShell脚本如何来创建存储账号(Storage Account)的共享访问签名呢?查询到可以使用 New-AzStorageContainerSASToken 命令来生成Az ...
- EFCore之命令行工具
介绍 EFCore工具可帮助完成设计数据库时候的开发任务,主要用于通过对数据库架构进行反向工程来管理迁移和搭建DbContext和实体类型.EFCore .NET命令行工具是对跨平台.NET Core ...
- JavaScript 最新动态:2024 年新功能
前言 随着 Web 技术的日新月异,JavaScript 也在不断地吸收新的特性和技术,以满足日益复杂和多样化的开发需求.在 2024 年,JavaScript 迎来了一系列令人瞩目的新功能,这些功能 ...
- WPF入门教程系列目录
WPF入门教程系列一--基础 WPF入门教程系列二--Application介绍 WPF入门教程系列三--Application介绍(续) WPF入门教程系列四--Dispatcher介绍 WPF入门 ...
- centos解决 pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available.
一.下载 openssl 编译安装 openssl 官方下载地址:https://www.openssl.org/source/ wget https://github.com/openssl/ope ...
- IDE中使用Git提交代码报错:Push to origin/release-V2 was rejected
一.问题由来 当前项目开发好之后,已经正常稳定运行一两个月,在使用过程中基本上没在出现什么BUG.因此公司在讨论准备开发二期项目,自己 就在之前的基础之上,使用git创建了分支,一个分支release ...
- keil5 调试
入口 复位 全速运行 先鼠标左键选中一行,然后点击就可以跳转到那一行 点击左侧灰色地带会生成断点,然后点击全速运行会到这个断点 查看动态参数 外设资源栏,可以看外设寄存器 点击运行,就可以实实查看寄存 ...
- Rust 标准库 Trait 指南
部分内容来自 Rust 2021 年期刊 内容目录 引言 Trait 基础 自动 Trait 泛型 Trait 格式化 Trait 操作符 Trait 转换 Trait 错误处理 迭代器 Trait ...
- 使用docker-compose管理freeswitch容器
概述 之前的文章我们介绍过如何将freeswitch做成docker镜像,也使用命令行模式正常启动了fs的docker容器. 但是当我们需要同时管理多个docker容器的时候,还是使用docker-c ...