2015-07-13 17 views
5

Ispirato dalla risposta a this SO question ho preso il codice per controllare un ciclo imperativo contro la ricorsione in coda:bytecode lento con la ricorsione in coda

let rec nothingfunc i = 
    match i with 
    | 1000000000 -> 1 
    | _ -> nothingfunc (i+1) 

let nothingloop1() = 
    let i = ref 0 in 
    while !i < 1000000000 do incr i done; 
    1 

let timeit f v = 
    let t1 = Unix.gettimeofday() in 
    let _ = f v in 
    let t2 = Unix.gettimeofday() in 
    t2 -. t1 

let() = 
    Printf.printf "recursive function: %g s\n%!" (timeit nothingfunc 0); 
    Printf.printf "while loop with ref counter buitin incr: %g s\n%!" (timeit nothingloop1()); 

Per bytecode e codice nativo i risultati sono

[email protected]:~> ./bench_loop 
recursive function: 20.7656 s 
while loop with ref counter buitin incr: 12.0642 s 
[email protected]:~> ./bench_loop.opt 
recursive function: 0.755594 s 
while loop with ref counter buitin incr: 0.753947 s 

La domanda è: qual è la ragione della grande differenza tra 20 e 12 secondi di esecuzione?

Modifica, mia conclusione:

Una chiamata di funzione apply (nel codice byte) prevede un controllo pila dimensioni, possibile allargamento pila, e un controllo per i segnali. Per le massime prestazioni, il compilatore del codice nativo fornirà.

(Nota a margine:. Chiedere qui su SO, perché è search engine friendly)

+1

opt in ocamlopt sta per ottimizzato. Il compilatore Bytecode esegue meno ottimizzazioni, in quanto non è mai stato il suo scopo. Sebbene molte ottimizzazioni siano ancora fatte. E, per esempio, sulla versione corrente del compilatore (4.03) la differenza è di circa il 10% (9.3 vs 8.3 secondi). – ivg

risposta

4

sguardo all'uscita del ocamlfind ocamlc -package unix test.ml -dlambda

(nothingloop1/1010 = 
    (function param/1022 
     (let (i/1011 =v 0) 
     (seq (while (< i/1011 100000000) (assign i/1011 (1+ i/1011))) 1))) 

(nothingfunc/1008 
    (function i/1009 
    (if (!= i/1009 100000000) (apply nothingfunc/1008 (+ i/1009 1)) 1))) 

Quindi, apparentemente assign è più veloce di apply. Sembra che ci siano controlli per lo stack overflow e segnali alle invocazioni di funzioni, ma non per un semplice assegnamento. Per i dettagli, è necessario guardare: https://github.com/ocaml/ocaml/blob/trunk/byterun/interp.c

+0

Ok, l'ho trovato. Sembra un interprete Forth. –

Problemi correlati