110 lines
4.7 KiB
Plaintext
110 lines
4.7 KiB
Plaintext
|
|
#pragma once
|
|||
|
|
|
|||
|
|
#include <cuda_runtime.h>
|
|||
|
|
#include <cublas_v2.h>
|
|||
|
|
#include <stdio.h>
|
|||
|
|
#include <stdlib.h>
|
|||
|
|
|
|||
|
|
#define OFFSET(row, col, ld) ((row)*(ld)+(col))
|
|||
|
|
#define FETCH_FLOAT4(pointer) (reinterpret_cast<float4*>(&(pointer))[0])
|
|||
|
|
|
|||
|
|
template<const int BM,
|
|||
|
|
const int BN,
|
|||
|
|
const int BK,
|
|||
|
|
const int TM,
|
|||
|
|
const int TN>
|
|||
|
|
__global__ void mysgemm_v6(int M, int N, int K, float alpha, float *A, float *B, float beta, float *C) {
|
|||
|
|
int bx = blockIdx.x;
|
|||
|
|
int by = blockIdx.y;
|
|||
|
|
|
|||
|
|
const int block_row_thread = BN / TN;
|
|||
|
|
const int block_col_thread = BM / TM;
|
|||
|
|
const int thread_num = block_row_thread * block_col_thread; // 一个线程负责计算block中TM*TN个元素
|
|||
|
|
|
|||
|
|
// 当前线程对应thread tile的左上角元素在block中的位置
|
|||
|
|
int tx = (threadIdx.x % block_row_thread) * TN;
|
|||
|
|
int ty = (threadIdx.x / block_row_thread) * TM;
|
|||
|
|
|
|||
|
|
__shared__ float As[BK * BM];
|
|||
|
|
__shared__ float Bs[BK * BN];
|
|||
|
|
|
|||
|
|
|
|||
|
|
const int ldg_a_num = BK * BM / thread_num / 4; // 每个线程搬运4个浮点数,完成搬运至As需要所有线程搬运ldg_a_num轮
|
|||
|
|
const int ldg_b_num = BK * BN / thread_num / 4; // 每个线程搬运4个浮点数,完成搬运至Bs需要所有线程搬运ldg_b_num轮
|
|||
|
|
|
|||
|
|
int a_tile_row = threadIdx.x / (BK / 4); // 每行4个字节作为一个内存块,当前线程负责第a_tile_row行的第a_tile_col个内存块的搬运
|
|||
|
|
int a_tile_col = threadIdx.x % (BK / 4) * 4;
|
|||
|
|
int a_tile_stride = BM / ldg_a_num; // 一共BM行,搬运ldg_a_num轮,每论搬运a_tile_stride行
|
|||
|
|
|
|||
|
|
int b_tile_row = threadIdx.x / (BN / 4); // 每行4个字节作为一个内存块,当前线程负责第b_tile_row行的第b_tile_col个内存块的搬运
|
|||
|
|
int b_tile_col = threadIdx.x % (BN / 4) * 4;
|
|||
|
|
int b_tile_stride = BK / ldg_b_num; // 一共BK行,搬运ldg_b_num轮,每论搬运b_tile_stride行
|
|||
|
|
|
|||
|
|
float accum[TM][TN] = {0.}; // 每个线程负责TM*TN个元素,则需要申请TM*TN个寄存器保存累加值,额外的一个寄存器用于缓存;
|
|||
|
|
|
|||
|
|
// 计算ldg_a_num的所有参数必须全部是const,否则不能用来申明数组大小
|
|||
|
|
float ldg_a_reg[4 * ldg_a_num] = {0.}; // 每个线程搬运ldg_a_num轮,寄存器缓存ldg_a_num个float4元素,用于转置As矩阵
|
|||
|
|
|
|||
|
|
float a_frag[TM]; // 缓存As共享内存
|
|||
|
|
float b_frag[TN]; // 缓存Bs共享内存
|
|||
|
|
|
|||
|
|
// 移动到当前block
|
|||
|
|
A = &A[by * BM * K];
|
|||
|
|
B = &B[bx * BN];
|
|||
|
|
C = &C[by * BM * N + bx * BN];
|
|||
|
|
|
|||
|
|
#pragma unroll
|
|||
|
|
for (int k = 0; k < K; k += BK) {
|
|||
|
|
#pragma unroll
|
|||
|
|
for (int i = 0; i < BM; i += a_tile_stride) {
|
|||
|
|
int ldg_index = i / a_tile_stride * 4; // 第ldg_index轮
|
|||
|
|
FETCH_FLOAT4(ldg_a_reg[ldg_index]) =
|
|||
|
|
FETCH_FLOAT4(A[OFFSET(a_tile_row + i, a_tile_col, K)]);
|
|||
|
|
// As转置存,其中ldg_a_reg做中间缓存,目的是读取时可以按FLOAT4读取
|
|||
|
|
As[OFFSET(a_tile_col, i + a_tile_row, BM)] = ldg_a_reg[ldg_index];
|
|||
|
|
As[OFFSET(a_tile_col + 1, i + a_tile_row, BM)] = ldg_a_reg[ldg_index + 1];
|
|||
|
|
As[OFFSET(a_tile_col + 2, i + a_tile_row, BM)] = ldg_a_reg[ldg_index + 2];
|
|||
|
|
As[OFFSET(a_tile_col + 3, i + a_tile_row, BM)] = ldg_a_reg[ldg_index + 3];
|
|||
|
|
}
|
|||
|
|
#pragma unroll
|
|||
|
|
for (int i = 0; i < BK; i += b_tile_stride) {
|
|||
|
|
FETCH_FLOAT4(Bs[OFFSET(b_tile_row + i, b_tile_col, BN)]) =
|
|||
|
|
FETCH_FLOAT4(B[OFFSET(b_tile_row + i, b_tile_col, N)]); // 不需要转置
|
|||
|
|
}
|
|||
|
|
__syncthreads();
|
|||
|
|
A += BK;
|
|||
|
|
B += BK * N;
|
|||
|
|
#pragma unroll
|
|||
|
|
for (int i = 0; i < BK; i++) {
|
|||
|
|
#pragma unroll
|
|||
|
|
for (int m = 0; m < TM; m += 4) {
|
|||
|
|
FETCH_FLOAT4(a_frag[m]) = FETCH_FLOAT4(As[OFFSET(i, ty + m, BM)]); // 偏移到当前thread tile
|
|||
|
|
}
|
|||
|
|
#pragma unroll
|
|||
|
|
for (int n = 0; n < TN; n += 4) {
|
|||
|
|
FETCH_FLOAT4(b_frag[n]) = FETCH_FLOAT4(Bs[OFFSET(i, tx + n, BN)]); // 偏移到当前thread tile
|
|||
|
|
}
|
|||
|
|
#pragma unroll
|
|||
|
|
for (int m = 0; m < TM; m++) {
|
|||
|
|
#pragma unroll
|
|||
|
|
for (int n = 0; n < TN; n++) {
|
|||
|
|
accum[m][n] += a_frag[m] * b_frag[n];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
__syncthreads();
|
|||
|
|
}
|
|||
|
|
#pragma unroll
|
|||
|
|
for (int m = 0; m < TM; m++) {
|
|||
|
|
#pragma unroll
|
|||
|
|
for (int n = 0; n < TN; n += 4) {
|
|||
|
|
float4 ctmp = FETCH_FLOAT4(C[OFFSET(ty + m, tx + n, N)]);
|
|||
|
|
//float4 atmp = FETCH_FLOAT4(accum[m][n]);
|
|||
|
|
ctmp.x = alpha * accum[m][n] + beta * ctmp.x;
|
|||
|
|
ctmp.y = alpha * accum[m][n + 1] + beta * ctmp.y;
|
|||
|
|
ctmp.z = alpha * accum[m][n + 2] + beta * ctmp.z;
|
|||
|
|
ctmp.w = alpha * accum[m][n + 3] + beta * ctmp.w;
|
|||
|
|
FETCH_FLOAT4(C[OFFSET(ty + m, tx + n, N)]) = ctmp;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|