|
이용태님이 쓰신 내용을 자세히 읽어보진 않았습니다만...
원래가 memset은 생각보다 상당히 느립니다.
기본적으로 byte단위로 복사하기 때문이죠. 예를 들어 4096바이트 크기의 배열을 모두 특정 byte값으로 채우는걸 생각해 본다면... 기본적으로 memset은 4096회의 대입연산을 수행합니다.
그러나 32bit컴퓨터의 특성을 생각해본다면 4배 더 빠르게 동작하도록 만드는 것이 가능하죠. 예를 들어 32 (0x20)을 채워넣는다고 하면
char arr[4096];
for (int i = 0; i < 4096; i++)
arr[i]=0x20;
이렇게 돌리는 방법이 일반적이지만...
char arr[4096];
DWORD *p = (DWORD*)arr;
for (int i=0; i < 1024; i++)
p[i] = 0x20202020;
이렇게 채우면... 1024회 루프로 4096개의 배열을 모두 채울 수 있습니다. 32bit컴퓨터에선 8bit를 대입하건 32bit를 대입하건 속도가 동일하죠. 물론 64bit OS에서는 LONGLONG 타입으로 처리하면 8배 빠르게 동작하게 만들 수 있습니다.
이 예제에서는 특정 값을 반복해서 채우는 것만 적용했지만 memcpy에도 충분히 적용 가능하다는걸 금방 눈치채실겁니다. 아무튼 mem으로 시작하는 기본 함수들은 대부분 곧이곧대로 채워넣는 방식이라서 속도가 느립니다.
Windows API로 있는 CopyMemory나 ZeroMemory등의 함수들은 소스를 볼 수 없으니 확신은 못합니다만... 예전에 제가 직접 구현한 여러가지 방식으로 속도테스트를 했던 결과로 보건데 제가 얘기한 방식으로 되어있는 듯 합니다. mem계열 함수보다 4배정도 빠릅니다.
다른분들의 조언처럼 다른 알고리즘의 최적화도 좋지만... 당연하게 사용하는 함수들의 성능에 대해서도 조금씩은 의문을 가지고 만들어보시면 좋을겁니다.
이용태 님이 쓰신 글 :
: 밑에 글에서 제가 설명을 자세히 하지 못한거 같아서 다시 글 올립니다.
:
: 자세히 설명을 하면요... 일단
:
: 원본 데이터는 다음과 같습니다.
:
: 데이터 셋트가 120개 있습니다. 한 셋트는 다시 데이터 4800개로 이루어집니다.
:
: 그러므로 총 데이터 포인트 수는 120개셋트 = 120*4800개입니다.
:
: a[120] [4800] <-- 원본 데이터
:
: 가로 120개..
: 세로 4800개로 다음과 같이 메모리 구조가 되어 있겠죠..(배열에 들어가 있는 값은 랜덤값으로 가정했습니다...)
: --->가로 120
: ___________________ ___________________
: 0|2|8|9|1|3|4|5|0|1 ---중간생략 --- 1|4|1|2|8|9|6
: 9|2|7|1|3|5|8|0|1|4 ----중간생략 --- 2|3|7|2|7|9|1
: | | |
: 중간생략 중간생략 중간생략
: | | |
: 0|1|5|7|2|5|6|7|9|4 ---중간생략 --- 1|5|7|2|7|8|0
: 8|2|2|2|3|3|7|1|2|4 ----중간생략 --- 1|2|3|2|1|2|4
: ___________________ ___________________
: 세로 4800
:
:
: 여기서 120*4800개의 데이터 한개한개를 가로로 100개씩 뻥튀기를 합니다..
:
: 그러면 총 데이터 개수는 120*100*4800입니다. 데이터 형은 BYTE 입니다.
:
: b[120*100][4800] <--- 가로로 100배 뻥튀기 된 데이터
:
: 메모리 구조는 다음과 같겠죠..
:
:
: 가로 120*100개
: ___________________ ___________________
: 0|0|0|0|0|0|0|0|0|0|2|2|2|2|2|2|2|2|2|2 ---중간생략 --- 9|9|9|9|9|9|9|9|9|6|6|6|6|6|6|6|6|6|6|
: 9|9|9|9|9|9|9|9|9|9|7|7|7|7|7|7|7|7|7|7 ----중간생략 --- 9|9|9|9|9|9|9|9|9|1|1|1|1|1|1|1|1|1|1|
: | | |
: 중간생략 중간생략 중간생략
: | | |
: 0|0|0|0|0|0|0|0|0|0|1|1|1|1|1|1|1|1|1|1| ---중간생략 --- 8|8|8|8|8|8|8|8|8|8|0|0|0|0|0|0|0|0|0|0
: 8|8|8|8|8|8|8|8|8|8|2|2|2|2|2|2|2|2|2|2| ----중간생략 --- 2|2|2|2|2|2|2|2|2|2|4|4|4|4|4|4|4|4|4|4
: ___________________ ___________________
: 세로 4800개
:
:
: 데이터 맵을 위와 같이 만들려고 하려다 보니... for()문을 돌려 원본 데이터(a[])로부터 일일히 해당 가로/인덱스에 해당하는 값을 읽어와 순차적으로 한개씩 값을 대입하는것보단 한꺼번에 범위로 값을 때려박는게 효율적이어서 memset()를 사용했던 것이죠...
:
: 이렇게 하여 데이터 맵을 만들어보니... memset()가 120*4800번 수행을 하게 되어 시간이 대략 0.23초 정도 걸리더군요..
:
: 데이터를 만든 후, 이미지 맵핑을 하고 각종 다른 부가 작업을 하니 시간이 0.32초 정도 걸립니다. 전체 작업에서 데이터 만드는 부분에서 무려 2/3의 시간을 잡아 먹게 되는거죠...
: 그래서 어떻게 해서든지 memset()보다 더 빠른 함수를 사용하던지 아니면 memset()를 적게 사용하는것이 답인거 같아서 여러가지 생각을 해봤습니다.
:
: memset()보다 빠른 함수를 찾지 못해서... memset()를 적게 사용할 수 있는 방법을 강구해봤습니다.
:
: 위의 데이터 그림에서와 같이.. 한셋트 데이터가 세로로 4800개씩.. 가로로 120개씩 늘어져 있는 모습입니다.
:
: 지금 방법은 각 데이터 포인트에 대해 memset()를 적용하여 뻥튀기를 했기 때문에 4800*120번 memset()을 사용하게 됩니다.
: 그런데 이것을 만약에 세로로 데이터 한셋트를 통채로 복사하여 가로로 복사를 하게 된다면 memset()를 120번만 수행하면 되죠...
:
: 그래서 어떻게 할 수 있을까 생각하면서 테스트를 해봤으나 도저히 방법이 떠오르지 않습니다.
:
: 배열에서 인접한 가로의 값을 긁어와 memcpy()로 복사 할 수 는 있지만.. 세로로 인접한 값은 한꺼번에 긁어오지 못하므로 memcpy()를 쓰지 못하더군요...
:
: 어떻게 하면 될까요?
:
: 0.23초는 너무 많이 걸립니다.. 0.1초 이하로 데이터 맵을 만들 수 있게끔 할려고 하는데요... 어떻게 하면 될까요??
|