λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ’» Programming/C++

[C++] ν–‰λ ¬κ³± μ—°μ‚° μ΅œμ ν™” 및 속도 비ꡐ

by 뭅즀 2022. 6. 30.
λ°˜μ‘ν˜•

C++ μ—μ„œ ν–‰λ ¬κ³± 연산을 κ΅¬ν˜„ν•  λ•Œ, μ—¬λŸ¬ 방법에 따라 속도 차이가 많이 λ‚œλ‹€κ³  ν•΄μ„œ κ°„λ‹¨ν•œ μ‹€ν—˜μœΌλ‘œ 속도 비ꡐλ₯Ό ν•΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€. ν–‰λ ¬κ³± μ—°μ‚° 과정은 λ”°λ‘œ μ„€λͺ…ν•˜μ§€ μ•Šκ³ , κ°€μž₯ λ‚˜μ΄λΈŒν•œ λ°©μ‹μ—μ„œ 속도λ₯Ό ν–₯μƒμ‹œν‚¬ 수 μžˆλŠ” λͺ‡κ°€μ§€ 방법듀을 λ‹¨κ³„μ μœΌλ‘œ μ„€λͺ…ν•©λ‹ˆλ‹€. 

 

사싀 ν–‰λ ¬ μ—°μ‚° μ‹œ 많이 μ‚¬μš©ν•˜λŠ” Eigen 라이브러리λ₯Ό μ“°λ©΄ μ΅œμ ν™”κ°€ μž˜λ˜μ–΄ μžˆμ–΄μ„œ μ‹€λ¬΄μ—μ„œ ν–‰λ ¬ 연산을 직접 κ΅¬ν˜„ν•΄μ•Όν•  상황이 μ–Όλ§ˆλ‚˜ μžˆλŠ”μ§€λŠ” 잘 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€. 아직 κ²½ν—˜μ΄ 많이 μ—†μ–΄μ„œ... γ… 

 

 

Baseline (naive version)

 

/*
@input
mat_x: m x k size matrix
mat_y: k x n size matrix
@output
mat_z: m x n size matrix 
*/

void matmult_baseline(int M, int N, int K, const float* mat_x, const float* mat_y, float* mat_z)
{
	for (int i = 0; i < M; i++)
		for (int j = 0; j < N; j++)
			for (int k = 0; k < K; k++)
				mat_z[N * i + j] += mat_x[i * K + k] * mat_y[k * N + j];
}

 

기본적인 ν–‰λ ¬κ³± 연산은 Aν–‰λ ¬μ˜ row와 B ν–‰λ ¬μ˜ column의 각 μ›μ†ŒλΌλ¦¬ κ³±ν•˜κ³  λ”ν•˜λŠ” κ³Όμ •μœΌλ‘œ κ΅¬μ„±λ©λ‹ˆλ‹€.
즉, 총 μ„Έκ°œμ˜ index(e.g. i,j,k)κ°€ ν•„μš”ν•˜μ—¬ 삼쀑 for문을 μˆœνšŒν•˜λ©° κ³„μ‚°ν•˜λ―€λ‘œ μ‹œκ°„ λ³΅μž‘λ„ (O^3) λ₯Ό κ°€μ§€λ―€λ‘œ 기본적으둜 연산이 λΉ λ₯΄μ§€λŠ” μ•Šκ² κ΅¬λ‚˜ 생각이 λ“­λ‹ˆλ‹€.
이 λ•Œ, μ €μž₯된 ν–‰λ ¬μ˜ μ›μ†Œλ₯Ό 행을 λ°”κΏ”κ°€λ©° ν˜ΈμΆœν•˜κ²Œ λ˜λŠ”λ° μ΄λŠ” cache λ©”λͺ¨λ¦¬λ₯Ό ꡉμž₯히 λΉ„νš¨μœ¨μ μœΌλ‘œ μ‚¬μš©ν•˜λŠ” 방법이기에 μ‹œκ°„μ΄ 였래 걸리게 λ©λ‹ˆλ‹€. 

 

 
Cache λ©”λͺ¨λ¦¬λŠ” μ‚¬μ΄μ¦ˆκ°€ μž‘κ³  μœ ν•œν•˜λ©° μ§€κΈˆ μ‚¬μš©ν•˜λŠ” μ£Όμ†Œκ°’ 근처의 값에 μ ‘κ·Όν•˜λŠ” κ²½μš°μ—λŠ” 효율적으둜 μ‚¬μš©μ΄ κ°€λŠ₯ν•˜μ§€λ§Œ, λ©€λ¦¬μžˆλŠ” μ£Όμ†Œκ°’μ— 반볡적으둜 μ ‘κ·Ό μ‹œ 효율이 λ–¨μ–΄μ Έ μ‹œκ°„μ΄ 였래 걸리게 λ©λ‹ˆλ‹€.
즉, ν–‰λ ¬ κ³± μ—°μ‚°μ‹œ rowλ₯Ό μ›€μ§μ΄λ©΄μ„œ μ›μ†Œμ— μ ‘κ·Όν•˜λ©΄ ν–‰λ ¬ μ‚¬μ΄μ¦ˆκ°€ 큰 κ²½μš°μ—λŠ” coulmn size * sizeof(~) 만큼 μ£Όμ†Œ 값을 μ΄λ™μ‹œμΌœμ•Όλ˜κΈ° λ•Œλ¬Έμ— λΉ„νš¨μœ¨μ μ΄κ²Œ λ©λ‹ˆλ‹€.

 

 

Indexing λ³€κ²½ : (IJK KIJ)

Baseline λ³΄λ‹€ cache λ©”λͺ¨λ¦¬λ₯Ό 효과적으둜 μ‚¬μš©ν•˜κΈ° μœ„ν•΄ indexing μˆœμ„œλ₯Ό λ³€κ²½ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€.
κΈ°μ‘΄ indexing (IJK) μ—μ„œ (KIJ)둜 λ³€κ²½ μ‹œ, κ°€μž₯ 많이 μˆœνšŒν•˜λŠ” λ§ˆμ§€λ§‰ for문을 보면 column을 μ›€μ§μ΄λ©΄μ„œ μ—°μ‚°ν•˜κΈ° λ•Œλ¬Έμ— row λ₯Ό μ›€μ§μ΄λ©΄μ„œ μ—°μ‚°ν•˜λŠ” 방법보닀 속도가 λΉ¨λΌμ§‘λ‹ˆλ‹€.
 
근데, 이런 트릭 μˆ˜μ€€μ˜ μ•Œκ³ λ¦¬μ¦˜ λ³€κ²½μœΌλ‘œ 속도가 μ–Όλ§ˆλ‚˜ 빨라질까 ν–ˆλŠ”λ°... ν–‰λ ¬ μ‚¬μ΄μ¦ˆκ°€ 컀질수둝 νš¨κ³Όκ°€ ꡉμž₯히 λ“œλΌλ§ˆν‹±ν•©λ‹ˆλ‹€. 

 

 

SIMD (Single Instruction Multiple Data) 적용

 

SIMDλŠ” CPU μ—μ„œ 병렬 연산을 ν•˜κΈ° μœ„ν•œ multiple dataλ₯Ό ν•œλ²ˆμ— μ—°μ‚°ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€.
μ–΄μ…ˆλΈ”λ¦¬μ–΄λ‘œ 직접 κ΅¬ν˜„ν•˜λŠ” 방법도 있고, μ–΄μ…ˆλΈ”λ¦¬μ–΄μ™€ 1λŒ€1 λ§€μΉ­λ˜λŠ” Intrinsic function 을 μ‚¬μš©ν•˜λŠ” 방법도 μžˆμŠ΅λ‹ˆλ‹€. Intrinsic function을 μ‚¬μš©ν•˜λŠ” 것이 비ꡐ적 νŽΈν•˜μ§€λ§Œ μžλ£Œν˜•λ³„λ‘œ μ‚¬μš©λ˜λŠ” ν•¨μˆ˜λ„ λ‹€λ₯΄κ³  ν•˜λ“œμ›¨μ–΄(컴퓨터ꡬ쑰)에 λŒ€ν•œ 기본적인 이해도가 ν•„μš”ν•©λ‹ˆλ‹€. 
즉, μ›μ†Œ ν•˜λ‚˜ ν•˜λ‚˜λ₯Ό μˆœνšŒν•˜λ©° κ³„μ‚°ν•˜λŠ” 방식이 μ•„λ‹ˆλΌ, μ—¬λŸ¬ μ›μ†Œμ˜ λ¬ΆμŒμ„ λ©”λͺ¨λ¦¬μ— μ˜¬λ €μ„œ(병렬적) ν•œλ²ˆμ— κ³„μ‚°ν•˜κΈ° λ•Œλ¬Έμ— 속도 ν–₯상을 κΈ°λŒ€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

 

GPU μ‚¬μš© (CUDA)

GPUλ₯Ό μ΄μš©ν•œ 병렬 ν”„λ‘œκ·Έλž˜λ°μ„ ν•˜κΈ° μœ„ν•΄ CUDA toolkit μ‚¬μš©ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€. λ”₯λŸ¬λ‹ ν•™μŠ΅μ‹œ μ•„μ£Ό κ°„λ‹¨ν•˜κ²Œ .cuda() 만 적으면 κ°„λ‹¨ν•˜κ²Œ μ‚¬μš©κ°€λŠ₯ν–ˆλ˜ GPUμ΄μ§€λ§Œ, C++ 의 κ²½μš°μ—λŠ” dataλ₯Ό CPU-GPU κ°„ λ³΅μ‚¬ν•˜κ³  λ©”λͺ¨λ¦¬λ₯Ό ν• λ‹Ήν•˜λŠ” 과정듀이 ν•„μš”ν•΄μ„œ 비ꡐ적 λ³΅μž‘ν•©λ‹ˆλ‹€.
 
ν•˜μ§€λ§Œ, κ°€μž₯ κ²°κ³Όκ°€ 쒋은 λ°©λ²•μž…λ‹ˆλ‹€.
 

* κΈ°λ³Έ μˆœμ„œ

1)Dataλ₯Ό CPU GPU 볡사
2)GPUμ—μ„œ kernel ν•¨μˆ˜ μ‹€ν–‰ν•˜μ—¬ μ—°μ‚°
3)κ²°κ³Όλ₯Ό GPUμ—μ„œ CPU 둜 볡사
 
 
 
 

μ‹€ν—˜ κ²°κ³Ό

 

 
λͺ¨λ“  μ‹€ν—˜μ€ (1000x1000 size matrix) * (1000x1000 size matrix) 의 ν–‰λ ¬κ³± μ—°μ‚°μ˜ 평균 μ†Œμš” μ‹œκ°„(ms)μž…λ‹ˆλ‹€.
CUDA λ°©λ²•μ˜ 경우 λ©”λͺ¨λ¦¬μ— μ˜¬λ¦¬λŠ” μ‹œκ°„κΉŒμ§€ ν¬ν•¨ν–ˆμŠ΅λ‹ˆλ‹€. (κ·Έλž˜λ„ μ••λ„μ μœΌλ‘œ λΉ λ¦…λ‹ˆλ‹€)
 
결둠만 μ •λ¦¬ν•˜λ©΄, Cache λ©”λͺ¨λ¦¬ 접근을 효과적으둜 ν•  λ•Œ(Indexing λ³€κ²½), λ³‘λ ¬ ν”„λ‘œκ·Έλž˜λ° μ‚¬μš©ν•  λ•Œ (SIMD), GPU μ‚¬μš©ν•  λ•Œ(CUDA) μ„±λŠ₯이 μ’‹μ•„μ§‘λ‹ˆλ‹€. 
 
CPU ν•œμ •μœΌλ‘œ 봀을 λ•Œ, Eigen λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μ—°μ‚° 속도가 μ’‹κ³  행렬을 닀루기 νŽΈν•˜κΈ° λ•Œλ¬Έμ— μ„ νƒμ˜ 여지가 없을 것 κ°™μŠ΅λ‹ˆλ‹€. 
 
 

 

λ°˜μ‘ν˜•