2016-07-07 6 views
3

밀도가 높은 비트 벡터 —을 나타내는 데 임의 정밀도 정수를 사용하고 있습니다. 에서부터 수천에 이르기까지입니다.프롤로그 : 비트가 설정되어 있는지 테스트

내 코드가 자주 특정 비트가 약간의 변화 속도가 매우 빠르고 다른 사람보다한다면, 그래서 내가 볼 수있는 몇 마이크로 벤치 마크를 한 설정 (또는)됩니다 있는지 확인해야

:

 
bench_1(0, _, _) :- !. 
bench_1(N, V, P) :- V /\ (1 << P) =\= 0, N0 is N-1, bench_1(N0, V, P). 

bench_2(0, _, _) :- !. 
bench_2(N, V, P) :- (V >> P) /\ 1 =:= 1, N0 is N-1, bench_2(N0, V, P). 

bench_3(0, _, _) :- !. 
bench_3(N, V, P) :- (V >> P) /\ 1 =\= 0, N0 is N-1, bench_3(N0, V, P). 

bench_4(0, _, _) :- !. 
bench_4(N, V, P) :- (V >> P) /\ 1 > 0, N0 is N-1, bench_4(N0, V, P). 

bench_5(0, _, _) :- !. 
bench_5(N, V, P) :- 1 is (V >> P) /\ 1, N0 is N-1, bench_5(N0, V, P). 

모두 SWI와 및 SICStus 위의 변형은 모두 (거의) 똑같이 빠릅니다.

는 그럼 다음 interesting part of the SWI-Prolog manual 우연히 :

getbit(+IntExprV, +IntExprI)

IntExprVIntExprI 번째 비트의 비트 값 (또는 0 1)로 평가. 두 인수 모두 음수가 아닌 정수로 평가되어야합니다. 결과는 (IntExprV >> IntExprI)/\1과 동일하지만, 시프트 된 값의 구체화가 방지되므로 더 효율적입니다.

향후 버전에서는 getbit/2으로 전화하여 (IntExprV >> IntExprI)/\1을 최적화하여 이식성과 성능을 모두 제공합니다. run(runtime, 10000000, 1<<1000-1, 200)

call_indi_delta(G, What, Delta) :- 
    statistics(What, [V0|_]), 
    call(G), 
    statistics(What, [V1|_]), 
    Delta is V1 - V0. 

run(Ind, Reps, Expr, Pos) :- 
    Position is Pos, 
    Value is Expr, 
    member(P_3, [bench_1,bench_2,bench_3,bench_4,bench_5,bench_6]), 
    G =.. [P_3,Reps,Value,Position], 
    call_indi_delta(G, Ind, T_ms), 
    write(P_3:Reps=T_ms), nl, 
    false. 

나는이 런타임 관찰 :

 
     | SWI | SWI -O | SICStus | SICStus | 
     | 7.3.23 | 7.3.23 | 4.3.2 | 4.3.3 | 
--------+-----------------+-------------------| 
bench_1 | 4547 ms | 3704ms | 900ms | 780ms | 
bench_2 | 4562ms | 3619ms | 970ms | 850ms | 
bench_3 | 4541ms | 3603ms | 970ms | 870ms | 
bench_4 | 4541ms | 3633ms | 940ms | 890ms | 
bench_5 | 4502ms | 3632ms | 950ms | 840ms | 
--------+-----------------+-------------------| 
bench_6 | 1424ms | 797ms | n.a. | n.a. | 
 
bench_6(0, _, _) :- !. 
bench_6(N, V, P) :- getbit(V,P) =:= 1, N0 is N-1, bench_6(N0, V, P). 

내가 마이크로 benchmarkng에 대한 다음 코드를 사용 :

그래서 나는 getbit/2을 체크 아웃

  • getbit/2는 SWI - 프롤로그에게 500 %의 속도 향상을 준 :것으로 보인다.

  • command-line option -O은 SWI-Prolog에 놀라운 속도 향상을 제공했습니다.

SICStus와 비슷한 속도 향상을 얻으려면 더 좋은 공식 (arith. fun. 등)이 있습니까?

미리 감사드립니다.

+2

SWI-Prolog ['mpz_tstbit' 사용] (https : // github .com/SWI-Prolog/swipl-devel/blob/198feb84f2218c90f1d7d98eca6f1fe60375e3ff/src/pl-arith.C# L2680)에서 [GMP] (https://gmplib.org/manual/Integer-Logic-and-Bit-Fiddling. html) (하단을보세요). SICStus가 다중 정밀도 정수를 구현하는 방법을 알고 있습니까? –

+0

@ 보리스. GMP를 알고 있지만 SWI가 어떻게 통합되는지 모르겠습니다. (저는 SWI 소스에서 여전히 길을 잃었습니다.) 링크를 가져 주셔서 감사합니다! SICStus에 관해서 : 나는 그것을 모른다. 그러나 나는 [tag : ffi]가 상당한 호출 오버 헤드를 초래한다는 직감을 가지고있다. 그러나 나는 확신 할 수 없다. 나는 그것을 확인하기 위해 C 인터페이스를 시도 할 것이다. – repeat

+2

SWI는 너무 큰 정수에는 GMP를 사용합니다. src/*. c에서 getbit를 grep하면 링크 된 코드 행을 찾을 수 있습니다. –

답변

4

아니요, 제가 시도한 것보다 빠른 공식화가 있다고 생각하지 않습니다. 특히, SICStus에는 getbit/2과 같은 것이 없습니다 (arithmetics를 컴파일 할 때 내부적으로 사용되지 않습니다).

추신. 일반적으로 벤치마킹을 위해 walltime을 사용합니다. 현재 운영 체제는 매우 안정적인 runtime을 제공하지 않습니다.

PPS.나는 테스트 된 코드 시퀀스의 더미 버전을 사용하는 벤치 마크를 추가하여 테스트 된 코드가 실제로 벤치마킹 하네스보다 훨씬 많은 비용을들이도록 보장합니다. (나는 그랬고 아무것도하지 않는 dummy/3에 대한 호출로 비트 테스트를 대체함으로써 훨씬 빨랐다. 따라서 벤치 마크는 괜찮은 것 같다.)

+0

Thx! [tag : ffi]를 사용해 볼까요? IIRC는 SICStus 4.3.2 (64 비트)의 JIT를 사용하여 호출 오버 헤드가 약간 높은 것으로 나타났습니다. – repeat

+0

'walltime'도 시도했습니다. 큰 비트 벡터 (IIRC GC 시간은'월시 (walltime) '의 일부 임)로 주목할만한 GC 오버 헤드를 볼 것으로 예상했다. 내가하지 않았다는 것에 놀랐다. – repeat

+2

@repeat 제 생각에는 fli가 너무 높은 오버 헤드를 가지며 (또한 C에서 큰 정수의 내용에 액세스하는 것은 무료가 아닙니다) 시도하는 것 없이는 알기 어렵습니다. –