2013-05-25 4 views
0

처음에는 파트 토론 부분 해결 형 질문 일 수 있습니다. 그 누구도 기분을 상하게 할 의도가 없습니다.부동 소수점 명령어로 부과되는로드를 이해하고 싶습니다.

64 비트 어셈블리에 MT Prime 기반 난수 생성기를 64 비트 생성하는 알고리즘을 작성했습니다.

이 발생 기능이 크기 2048x2048x2048의 배열을 채우고 1..small_value 사이의 임의의 어떤을 생성하기 위해 80 억 번 호출 할 필요가있다 (보통, 32)

는 지금은 두 다음 단계의 가능성이 있었다 (a) 숫자를 생성하고 제한값 [1..32]과 비교하여 그 범위를 벗어나는 값을 버린다. 이 로직의 실행 시간은 clock() 함수를 호출하여 측정 한 181,817ms입니다.

(b) RAX에서 출력되는 64 비트 난수를 가져 와서 FPU를 사용하여 [0..1] 사이의 값으로 스케일 한 다음 원하는 범위 [1..32]로 스케일합니다. 코드 시퀀스

mov word ptr initialize_random_number_scaling,dx 
fnclex    ; clears status flag 
call generate_fp_random_number ; returns a random number in ST(0) between [0..1] 
fimul word ptr initialize_random_number_scaling ; Mults ST(0) & stores back in ST(0) 
mov word ptr initialize_random_number_base,ax ; Saves base to a memory 
fiadd word ptr initialize_random_number_base ; adds the base to the scaled fp number 
frndint       ; rounds off the ST(0) 
fist word ptr initialize_random_number_result ; and stores this number to result. 
ffree st(0)    ; releases ST(0) 
fincstp      ; Logically pops the FPU 
mov ax, word ptr initialize_random_number_result  ; and saves it to AX 

그리고 generate_fp_random_number의 지침은 다음과 같습니다 :이 다음과 같습니다에 대한

shl rax,1 ; RAX gets the original 64 bit random number using MT prime algorithm 
shr ax,1 ; Clear top bit 
mov qword ptr random_number_generator_act_number,rax ; Save the number in memory as we cannot move to ST(0) a number from register 
fild qword ptr random_number_generator_max_number ; Load 0x7FFFFFFFFFFFFFFFH 
fild qword ptr random_number_generator_act_number ; Load our number 
fdiv st(0),st(1) ; We return the value through ST(0) itself, divide our random number with max possible number 
fabs 
ffree st(1) ; release the st(1) 
fld1   ; push to top of stack a 1.0 
fcomip st(0), st(1) ; compares our number in ST(1) with ST(0) and sets CF. 
jc generate_fp_random_get_next_no ; if ST(0) (=1.0) < ST(1) (our no), we need a new no 
fldz    ; push to top of stack a 0.0 
fcomip st(0),st(1) ; if ST(0) (=0.0) >ST(1) (our no) clears CF 
jnc generate_fp_random_get_next_no ; so if the number is above zero the CF will be set 
fclex 

문제는 바로 이러한 지침을 추가하여,이다, 실행 시간은 무려 5,633,963 MS로 이동합니다! 나는 대안으로 xmm 레지스터를 사용하여 위 코드를 작성했으며 그 차이는 절대적으로 적다. (5,633,703 ms).

누구나 친절하게도이 추가 지침이 전체 실행 시간에 어느 정도 부하를 걸 었는지에 관해 안내해 줄 수 있습니까? FPU가 정말로 느린가? 아니면 트릭을 놓치고 있습니까? 항상 그렇듯이 모든 아이디어는 환영하며 시간과 노력에 감사드립니다.

봉투 : "MOV 단어의 PTR initialize_random_number_base, 도끼, 메모리에 기반을 저장합니다"윈도우 7 64 비트 인텔에 2700K CPU는 16기가바이트 RAM은 VS 2012 익스프레스 환경

답변

0

에서 디버깅 4.4 GHz까지 오버 클럭

하는 경우 당신은 상황이 쓰기 명령을 분리 캐시의 같은 지역에 데이터를 재 작성

는 "자체 수정 코드"를 만들어 메모리의 다른 섹션에 데이터를 작성하는 방법을 발견해야 최대 속도를 원하는

컴파일러가이를 수행 할 수도 있습니다. 그렇지 않을 수도 있습니다. 최적화되지 않은 어셈블리 코드가 10에서 50 배 더 느리게 실행되기 때문에이를 알아야합니다.

"최신 프로세서는 모두 코드와 데이터 메모리를 효율적으로 캐시합니다. 데이터가 동일한 블록에 쓰여질 경우 어셈블리 언어 코드의 성능이 심각하게 저하 될 수 있습니다 CPU가 반복적으로 명령 캐시를 다시로드하게 할 수 있기 때문에 코드가 실행되는 메모리와 동일하게 사용됩니다 (이는 자동 수정 코드가 올바르게 작동하는지 확인하기위한 것입니다).이를 방지하려면 코드 및 (쓰기 가능한) 데이터는 메모리의 같은 2 킬로바이트 블록을 차지하지 않습니다. "

http://www.bbcbasic.co.uk/bbcwin/manual/bbcwina.html#cache

+0

이것은 자체 수정 코드가 아니며 어셈블리에도 완전히 쓰여 있습니다. 변수 initialize_random_number_base는 데이터 세그먼트에서 정의 단어로 선언됩니다.이 값은 2K보다 훨씬 큽니다. 그러나주의는 정말로 유용합니다. 고마워. 따라서 데이터 세그먼트에 불필요한 공간을 추가 했으므로 코드 세그먼트와 2K가 넘습니다. – quasar66

0

코드에서 물건의 톤이있다 나는 아무 이유도 볼 수 없다.이유가 있었다면, 정정 해줘 주시기하지만, 그 여기 내 대안 :

mov word ptr scaling, dx 
mov word ptr base, ax 
call generate_fp_random_number 
fimul word ptr scaling 
fiadd word ptr base 
fistp word ptr result ; just save that thing 
mov ax, word ptr result 
; the default rounding mode is round to nearest, 
; so the slow frndint is unnecessary 

는 또한의 전체 부족을주의 : 다른 일에 대한 generate_fp_random_number

shl rax, 1 
shr rax, 1 
mov qword ptr act_number, rax 
fild qword ptr max_number 
fild qword ptr act_number 
fdivrp ; divide actual by max and pop 
; and that's it. It's already within bounds. 
; It can't be outside [0, 1] by construction. 
; It can't be < 0 because we just divided two positive number, 
; and it can't be > 1 because we divided by the max it could be 

를 들어

ffree 님의 등. 올바른 지시 사항을 적용함으로써 모든 것이 효과가있었습니다. 보통 그렇습니다.

+0

조언을 주셔서 감사합니다 - 예, 아마도 한계 등등에 대해 너무 보수적이었습니다. 또한 fdivrp를 심각하게 살펴 보지 않았습니다. 변경을 수행하고 프로세스를 시작한 후 완료되면 타이밍을 업데이트해야합니다. – quasar66