Lab 3
Lab 3
Мөнх-Оргил Lab 3
#include "/content/hpc_helpers.hpp"
std::mt19937 engine(42);
std::uniform_real_distribution<float> density(-1, 1);
void plain_dmm(float * A,
float * B,
float * C,
uint64_t M,
uint64_t L,
uint64_t N,
bool parallel) {
void avx_dmm(float * A,
float * B,
float * C,
uint64_t M,
uint64_t L,
uint64_t N,
bool parallel) {
__m256 X = _mm256_setzero_ps();
for (uint64_t k = 0; k < L; k += 8) {
const __m256 AV = _mm256_load_ps(A+i*L+k);
const __m256 BV = _mm256_load_ps(B+j*L+k);
X = _mm256_add_ps(X, _mm256_mul_ps(AV, BV));
}
C[i*N+j] = hsum_avx(X);
}
}
void avx2_tmm(float * A,
float * B,
float * C,
uint64_t M,
uint64_t L,
uint64_t N,
bool parallel) {
#pragma omp parallel for collapse(2) if(parallel)
for (uint64_t i = 0; i<M; i++)
for (uint64_t j=0; j<N; j++) {
__m256 X = _mm256_setzero_ps();
for (uint64_t k = 0; k < L; k += 8) {
const __m256 AV = _mm256_load_ps(A+i*L+k);
const __m256 BV = _mm256_load_ps(B+j*L+k);
X = _mm256_fmadd_ps(X, _mm256_mul_ps(AV, BV));
}
C[i*N+j] = hsum_avx(X);
}
}
void avx_dmm_unroll_2(float * A,
float * B,
float * C,
uint64_t M,
uint64_t L,
uint64_t N,
bool parallel) {
__m256 X = _mm256_setzero_ps();
__m256 Y = _mm256_setzero_ps();
for (uint64_t k = 0; k < L; k += 16) {
const __m256 AVX = _mm256_load_ps(A+i*L+k+0);
const __m256 BVX = _mm256_load_ps(B+j*L+k+0);
const __m256 AVY = _mm256_load_ps(A+i*L+k+8);
const __m256 BVY = _mm256_load_ps(B+j*L+k+8);
X = _mm256_add_ps(X, _mm256_mul_ps(AVX, BVX));
Y = _mm256_add_ps(X, _mm256_mul_ps(AVY, BVY));
}
C[i*N+j] = hsum_avx(X)+hsum_avx(Y);
}
}
int main () {
TIMERSTART(alloc_memory)
auto A = static_cast<float*>(_mm_malloc(M*L*sizeof(float) , 32));
auto B = static_cast<float*>(_mm_malloc(N*L*sizeof(float) , 32));
auto C = static_cast<float*>(_mm_malloc(M*N*sizeof(float) , 32));
TIMERSTOP(alloc_memory)
TIMERSTART(init)
init(A, M*L);
init(B, N*L);
TIMERSTOP(init)
TIMERSTART(plain_dmm_single)
plain_dmm(A, B, C, M, L, N, false);
TIMERSTOP(plain_dmm_single)
TIMERSTART(plain_dmm_multi)
plain_dmm(A, B, C, M, L, N, true);
TIMERSTOP(plain_dmm_multi)
TIMERSTART(avx_dmm_single)
avx_dmm(A, B, C, M, L, N, false);
TIMERSTOP(avx_dmm_single)
TIMERSTART(avx_dmm_multi)
avx_dmm(A, B, C, M, L, N, true);
TIMERSTOP(avx_dmm_multi)
TIMERSTART(avx2_tmm_single)
avx2_tmm(A, B, C, M, L, N, false);
TIMERSTOP(avx2_tmm_single)
TIMERSTART(avx2_tmm_multi)
avx2_tmm(A, B, C, M, L, N, true);
TIMERSTOP(avx2_tmm_multi)
TIMERSTART(avx_dmm_unroll_2_single)
avx_dmm_unroll_2(A, B, C, M, L, N, false);
TIMERSTOP(avx_dmm_unroll_2_single)
TIMERSTART(avx_dmm_unroll_2_multi)
avx_dmm_unroll_2(A, B, C, M, L, N, true);
TIMERSTOP(avx_dmm_unroll_2_multi)
TIMERSTART(free_memory)
_mm_free(A);
_mm_free(B);
_mm_free(C);
TIMERSTOP(free_memory)
}
Overwriting transs.cpp
Дүгнэлт
Энэхүү даалгавараар Лекц 5-дээр үзсэн AVX2 ийн Transpose-and-Multiply алгоритм ийг хэрэгжүүлж, хэр их хугацаа өнгөрсөнг хэвлэж гаргав.
Зөвхөн AVX2 биш сурах бичиг дээр байгаа бусад алгоритмийн хамт ажиллуулж, харицуулсан болно.
Жирийн AVX transpose & multiply single алгоритм нь 8.4705s бол parallel нь 8.55333s зарцуулсан. AVX2 transpose & multiply алгоритм болох
avx2_tmm_single нь 8.6349s бол avx2_tmm_multi нь 8.65955s зарцуулсан болно.
Энэхүү хариу миний ашиглаж байгаа интернетээс хамаарч өөр гарсан байх боломжтой
std::mt19937 engine(42);
std::uniform_real_distribution<float> density(-1, 1);
M03 = _mm256_castps128_ps256(M[0]);
M14 = _mm256_castps128_ps256(M[1]);
M25 = _mm256_castps128_ps256(M[2]);
R = _mm256_rsqrt_ps(R);
X = _mm256_mul_ps(X, R);
Y = _mm256_mul_ps(Y, R);
Z = _mm256_mul_ps(Z, R);
M[0] = _mm256_castps256_ps128(R03);
M[1] = _mm256_castps256_ps128(R14);
M[2] = _mm256_castps256_ps128(R25);
M[3] = _mm256_extractf128_ps(R03, 1);
M[4] = _mm256_extractf128_ps(R14, 1);
M[5] = _mm256_extractf128_ps(R25, 1);
}
}
TIMERSTART(alloc_memory)
auto xyz = static_cast<float*>(_mm_malloc(num_bytes , 32));
TIMERSTOP(alloc_memory)
TIMERSTART(init)
aos_init(xyz, num_vectors);
TIMERSTOP(init)
TIMERSTART(avx_aos_normalize)
avx_aos_norm(xyz, num_vectors);
TIMERSTOP(avx_aos_normalize)
TIMERSTART(check)
aos_check(xyz, num_vectors);
TIMERSTOP(check)
TIMERSTART(free_memory)
_mm_free(xyz);
TIMERSTOP(free_memory)
}
Overwriting aos.cpp
tcmalloc: large alloc 3221225472 bytes == 0x55c36aa4a000 @ 0x7f4768478b6b 0x7f4768498379 0x55c369825bfb 0x55c3698263
db 0x7f476796cc87 0x55c369825aba
Дүгнэлт
Лекц 6-дээр үзсэн AoS дээрх Vectorized нормалчлал гэсэн параллел алгоритмыг хэрэгжүүлэв.
Санах ой бэлдэх хугацаа, Initialization хийх хугацаа, avx_aos_normalize хугацаа, шалгах хугацаа, санах ойг суллах хугацааг хэвлэж
харуулав.
AOS форматад 3D векторыг 256 бит регистр SoA формат руу шилжүүлнэ. SoA форматыг ашиглан Vectorized SIMD тооцооллоно. SoA ээс үр
дүнг AoS формат руу шилжүүлнэ. Векторыг холих үйлдэл ашиглана.
Ашигласан Материал
Сурах бичиг: An Introduction to Modern Parallel Programming