티스토리 뷰
안녕하세요. Teus입니다.
이번 포스팅은 SIMD(Single Instrunction Multi Data)를 다룹니다.
이번에는 AVX를 Array로 사용하지않고, Pointer를 사용하는 패턴을 보도록 하겠습니다.
1. _aligned_malloc
_aligned_malloc(size_t data_size, size_t alignemnet_size)
aligned_malloc은 기본적인 malloc과 다르게 alignement_size 만큼 Data끼리의 간격을 보장해주는 Malloc을 의미합니다.
일반적으로 16byte, 32byte씩 Data를 띄워주면 SIMD의 Data처리 효율이 증가한다고 알려져 있습니다.
__m256d* arr1 = (__m256d*)_aligned_malloc(sizeof(double) * data_num, 32);
2. Data의 초기화
malloc으로 Data를 할당받을 경우 보통 쓰레기값으로 Data가 차 있습니다.
이때 Data를 초기화 시켜야지 내가 원하는 연산을 할 수 있겠죠?
이때 초기화 시킬때
- 동일한 값으로 채우기
- 다른 array를 사용해서 가지고오기
를 생각해볼 수가 있습니다.
다른 값으로 채워오기는
함수 | Description |
---|---|
_mm256_set1_ps/pd | 256bit을 64/32bit의 값으로 broadcast |
_mm256_set1_epi8/16/32/64x/ps/pd | 해당 Vector를 입력한 값으로 broadcast |
_mm256_setzero_pd/ps/si256i | type에 맞는 0채워진 Vector를 반환 |
다른 Array에 있는 값을 가지고 올때는 이전에 사용했던 함수들을 사용합니다.
함수 | Description |
---|---|
_mm256_set_epi8/16/32/64x/pd/ps | 256/data_size 만큼의 Element를 입력하고, 해당 값으로 Vector를 초기화시킴 |
_mm256_setr_epi8/16/32/64x/pd/ps | 위 함수와 reverse순으로 Data를 기록시킴 |
_mm256_set_m128i/m128d/m128 | 256bit의 값을 상위 128bit은 첫번째 값, 하위 128bit은 두번째 값으로 채움 |
주의사항이, set을 사용할 경우 마지막 매개변수가 첫번째 값이 됩니다.
_mm256_set_ps
그래서 사람이 인지하기 쉽게 하기 위해서 setr이 주로 사용되게 됩니다.
for (int i = 0; i < data_num / 4; i++) {
/*
simd의 native routine을 사용하는 방법
_mm256_store_pd((double*)&ret[i], _mm256_setzero_pd());
_mm256_store_pd((double*)&arr1[i], _mm256_setzero_pd());
_mm256_store_pd((double*)&arr2[i], _mm256_setzero_pd());
*/
//pointer를 바로 사용할 경우
ret[i] = _mm256_setzero_pd();
arr1[i] = _mm256_setzero_pd();
arr2[i] = _mm256_setzero_pd();
}
3. 연산하기
연산 부분에서는 이제 반복문으로 접근하여
Vecotr를 가지고오고, 연산을 하게 됩니다.
이전 예제코드에서는 Vector하나만 존재했기 때문에 반복문이 필요 없었지만
pointer를 사용하여 연산할 경우 2개 이상의 Vector를 사용하기 때문에
Pointer를 사용해서 Data에 접근하고, _mm256_add_pd
와 같은 SIMD 연산자를 사용하게 됩니다.
for (int i = 0; i < data_num / 4; i++) {
/*
simd의 native routine을 사용하는 방법
__m256d first_val = _mm256_load_pd((double*)&arr1[i]);
__m256d second_val = _mm256_load_pd((double*)&arr2[i]);
__m256d ret_values = _mm256_add_pd(first_val, second_val);
_mm256_store_pd((double*)&ret[i], ret_values);
*/
//pointer를 바로 사용할 경우
ret[i] = _mm256_add_pd(arr1[i], arr2[i]);
}
위까지 사용한 코드를 이제 종합 해 보겠습니다.
아래 코드는 Pointer를 사용해서 새롭게 Memory를 할당받고
할당받은 Memory를 0으로 초기화하고, SIMD Add연산을 하는 예제 입니다.
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <xmmintrin.h>
#include <immintrin.h >
int data_num = 1000000;
int main() {
__m256d* arr1 = (__m256d*)_aligned_malloc(sizeof(double) * data_num, 32);
__m256d* arr2 = (__m256d*)_aligned_malloc(sizeof(double) * data_num, 32);
__m256d* ret = (__m256d*)_aligned_malloc(sizeof(double) * data_num, 32);
for (int i = 0; i < data_num / 4; i++) {
/*
_mm256_store_pd((double*)&ret[i], _mm256_setzero_pd());
_mm256_store_pd((double*)&arr1[i], _mm256_setzero_pd());
_mm256_store_pd((double*)&arr2[i], _mm256_setzero_pd());
*/
ret[i] = _mm256_setzero_pd();
arr1[i] = _mm256_setzero_pd();
arr2[i] = _mm256_setzero_pd();
}
for (int i = 0; i < data_num / 4; i++) {
double* _ret = (double*)&ret[i];
double* _arr1 = (double*)&arr1[i];
double* _arr2 = (double*)&arr2[i];
for (int j = 0; j < 4; j++) {
printf("i = %d, j = %d, ret = %f, arr1 = %f, arr2 = %f\n", i, j, _ret[j], _arr1[j], _arr2[j]);
}
}
for (int i = 0; i < data_num / 4; i++) {
/*
__m256d first_val = _mm256_load_pd((double*)&arr1[i]);
__m256d second_val = _mm256_load_pd((double*)&arr2[i]);
__m256d ret_values = _mm256_add_pd(first_val, second_val);
_mm256_store_pd((double*)&ret[i], ret_values);
*/
ret[i] = _mm256_add_pd(arr1[i], arr2[i]);
}
}
'C언어 잡기술 > SIMD(AVX)' 카테고리의 다른 글
AVX 튜토리얼5. Permuting/Shuffling연산 (0) | 2024.04.24 |
---|---|
AVX 튜토리얼4. FMA연산 (0) | 2024.04.24 |
AVX 튜토리얼3. mul/divide연산 (0) | 2024.04.24 |
AVX 튜토리얼2. Add/Sub연산 (0) | 2024.04.24 |
AVX 튜토리얼1. DataType (0) | 2024.04.02 |
- Total
- Today
- Yesterday
- GDC
- 코딩테스트
- Search알고리즘
- AVX
- 분할정복
- 자료구조
- 프로그래머스
- C++
- 이분탐색
- hash
- 알고리즘
- 병렬처리
- heap
- prime number
- SIMD
- Greedy알고리즘
- 완전탐색 알고리즘
- 동적계획법
- 컴퓨터그래픽스
- 사칙연산
- Python
- Sort알고리즘
- git
- stack
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |