구글애드센스


메모리 성능에 대한 고찰 feat.memcpy STUDY




주로하는 일이 영상 관련된 핸들링이다보니 메모리 카피를 빈번하게 사용한다.
최종적으로는 프로토콜에 실어 보내야 하는 경우가 많으니 적어야 두번정도는 memcpy를 호출하게 된다.
이것은 곧 성능으로 이어지고 복사 작업 때문에 영상 encoding/decoding 성능이 느려지는 상황도 종종 조우하게 된다.

그냥 끄적끄적 놀던 도중, 메모리 카피를 병렬로 처리하면(?) 빠르지 않을까 갑자기 번쩍하고 아이디어가 떠올라 테스트해봤다.

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <string.h>
#include <stdlib.h>

#include <boost/chrono.hpp>
#include <boost/thread.hpp>

#define TARGET_MEMORY (INT_MAX)

void copythread(char* pBuffer, char* pTargetBuffer, int i)
{
memcpy(&pTargetBuffer[(TARGET_MEMORY / 12) * i], &pBuffer[(TARGET_MEMORY / 12) * i],TARGET_MEMORY / 12);
}

int main(void)
{
char* pBuffer = new char[TARGET_MEMORY];
char* pTargetBuffer = new char[TARGET_MEMORY];
int nElapsed = 0;
boost::chrono::system_clock::time_point tpPreTick;

memset(pBuffer, 0x10, TARGET_MEMORY);
memset(pTargetBuffer, 0x10, TARGET_MEMORY);

// Memory copy
tpPreTick = boost::chrono::system_clock::now();
memcpy(pTargetBuffer, pBuffer, TARGET_MEMORY);
nElapsed = boost::chrono::duration_cast<boost::chrono::milliseconds>
(boost::chrono::system_clock::now() - tpPreTick).count();
std::cout << "MEMCPY ELAPSED : " << nElapsed << " ms" << std::endl;

// Memory copy with openmp
tpPreTick = boost::chrono::system_clock::now();
#pragma omp parallel for num_threads(12)
for (int i = 0 ; i < 12 ; i++)
memcpy(&pTargetBuffer[(TARGET_MEMORY / 12) * i], &pBuffer[(TARGET_MEMORY / 12) * i],TARGET_MEMORY / 12);
nElapsed = boost::chrono::duration_cast<boost::chrono::milliseconds>
(boost::chrono::system_clock::now() - tpPreTick).count();
std::cout << "PARALLEL MEMCPY ELAPSED : " << nElapsed << " ms" << std::endl;

// Memory copy with threads
tpPreTick = boost::chrono::system_clock::now();
boost::thread_group threads;
for (int i = 0 ; i < 12 ; i++)
threads.create_thread(boost::bind(&copythread, pBuffer, pTargetBuffer, i));
threads.join_all();
nElapsed = boost::chrono::duration_cast<boost::chrono::milliseconds>
(boost::chrono::system_clock::now() - tpPreTick).count();
std::cout << "Threading MEMCPY ELAPSED : " << nElapsed << " ms" << std::endl;

delete [] pBuffer;
delete [] pTargetBuffer;

return 0;
}


빌드는 아래처럼 해봤다.

1
g++ -o pm pm.cpp -fopenmp -lboost_system -lpthread -lboost_chrono -lboost_thread

결과는 아래와 같다.

[muzie@sv01 Works]$ ./pm
MEMCPY ELAPSED : 248 ms
PARALLEL MEMCPY ELAPSED : 110 ms
Threading MEMCPY ELAPSED : 110 ms
[muzie@sv01 Works]$

참고로, 쓰레드 개수나 openmp의 cpu 개수를 12개로 둔 이유는 우리 개발서버의 CPU 개수에 맞췄기 때문이다.

결과에서 볼 수 있듯이 대략 50%정도의 성능향상을 기대할 수 있었다. 이 정도면 진짜 말도 안되는 수치인데 -_-;
CPU 자원 모니터링을 좀 해보면서 확인 해봐야 할 것 같다.



덧글

댓글 입력 영역