자기개발/SIMD

SIMD - 최대값 구하기( C랑 비교)

pi92 2021. 10. 8. 10:33
int main(int argc, char* argv[])
{
	clock_t start_c, end_c;									// C언어 속도 측정을 위한 변수들
	clock_t start_simd, end_simd;							// SIMD 속도 측정을 위한 변수들

	const int MAX_SIZE = 100000000;							// 1억개 비교

	short* pShortArray = new short[MAX_SIZE];				//MAX_SIZE 만큼 배열 생성
	memset(pShortArray, 0x00, MAX_SIZE * sizeof(short));	//모든 배열에 0x00(0) 값을 대입

	pShortArray[9000003] = 100;								// 9000003번째 값에만 100 대입

	int nResult = 0;										//최대값 넣기 위한 변수

	// c로 만든 GetMaxValueC
	start_c = clock();
	nResult = GetMaxValueC(pShortArray, MAX_SIZE);
	end_c = clock();

	cout << " C Get Value : " << nResult << ", Time : " << (end_c - start_c)/1000 << endl;

	//SIMD로 만든 GetMaxValueSIMD
	start_simd = clock();
	nResult = GetMaxValueSIMD(pShortArray, MAX_SIZE);
	end_simd = clock();

	cout << "SIMD Get Value : " << nResult << ", Time : " << (end_simd - start_simd)/1000 << endl;

	delete[] pShortArray;

	return 0;
}

C로 만든 함수

 

//c로 만든 함수
short GetMaxValueC(const short *pShortArray, const int nSize)
{
	short MaxValue = 0;					//return 값
	for (int i = 0; i < nSize; i++)		//배열 크기만큼 반복
	{
		if (pShortArray[i] > MaxValue)	//현재 값과 이전 MaxValue 값 비교
			MaxValue = pShortArray[i];	//현재 값이 크면 값 대입
	}
	return MaxValue;					//결과 리턴
}

 

SIMD 사용

//SIMD 사용
short GetMaxValueSIMD(const short *pShortArray, const int nSize)
{
	const short* pShort = pShortArray;	//스택 포인터 변수로 받아온다.

	int nLoopCount = (nSize / 8) * 16;	//8배수 개수를 한 번에 계산(한개당 16bit)
	int nRemain = nSize % 8;			//8배수 나머지 영역은 C로 구현

	short nMaxValue = 0;				//결과값을 가지고 있을 메모리 변수

	short MaxValueArray[8] = { 0 };		//중간 결과값을 담을 배열

	__asm								//어셈블리
	{
		pushad
		mov eax, pShort					// eax = pShort; 
										// 자료구조 포인터를 레지스터에 옮긴다.
		mov esi, 0						// esi = 0; 
										//자료구조를 indexing할 레지스터 초기화
		mov ecx, nLoopCount				// ecx = nLoopCount; 
										//순환 연산 Limit 값을 담을 변수
		pxor xmm1, xmm1					// xmm1 = 0; //결괏값을 담을 레지스터 변수 초기화

	FINDLP:
		movdqu xmm0, [eax+esi]			//xmm0 에 현재 값을 가져온다.
										//xmm0  = *(eax+esi);
		pmaxsw xmm1, xmm0				//8배수 만큼 각각 비교하여 xmm1에 최대값을 넣는다.
										//xmm1 = __max( xmm0, xmm1) 
		add esi, 16						//다음 주소만큼 추가
										//esi = esi + 16;
		cmp esi, ecx					//jne 일 경우 if( esi != ecx)
		jne FINDLP						//goto FINDLP

		movdqu MaxValueArray, xmm1		//MaxValueArray = xmm1;

		popad
	}

	for (unsigned char Count = 0; Count < 8; Count++)
	{
		//xmm1 에서 구한 값 8개를 비교하여 최종 결괏값을 구한다.
		if (MaxValueArray[Count] > nMaxValue)
			nMaxValue = MaxValueArray[Count];
	}
	if (nRemain != 0)	//8의 배수가 아닌 나머지 값이 있으면 max 값 비교를 수행
	{
		for (int i = nSize - nRemain; i < nSize; i++)
		{
			if(pShortArray[i] > nMaxValue)
				nMaxValue = pShortArray[i];
		}
	}

	return nMaxValue;
}

메인함수

 

int main(int argc, char* argv[])
{
	clock_t start_c, end_c;									// C언어 속도 측정을 위한 변수들
	clock_t start_simd, end_simd;							// SIMD 속도 측정을 위한 변수들

	const int MAX_SIZE = 100000000;							// 1억개 비교

	short* pShortArray = new short[MAX_SIZE];				//MAX_SIZE 만큼 배열 생성
	memset(pShortArray, 0x00, MAX_SIZE * sizeof(short));	//모든 배열에 0x00(0) 값을 대입

	pShortArray[9000003] = 100;								// 9000003번째 값에만 100 대입

	int nResult = 0;										//최대값 넣기 위한 변수

	// c로 만든 GetMaxValueC
	start_c = clock();
	nResult = GetMaxValueC(pShortArray, MAX_SIZE);
	end_c = clock();

	cout << " C Get Value : " << nResult << ", Time : " << (float)(end_c - start_c) / 1000 << "(s)" << endl;

	//SIMD로 만든 GetMaxValueSIMD
	start_simd = clock();
	nResult = GetMaxValueSIMD(pShortArray, MAX_SIZE);
	end_simd = clock();

	cout << "SIMD Get Value : " << nResult << ", Time : " << (float)(end_simd - start_simd) / 1000 << "(s)" << endl;

	delete[] pShortArray;

	return 0;
}

결과

 

책에선 2배정도 차이난것같은데 10배차이나네..??