2015-07-13 7 views
5

durch die Antwort inspiriert zu this SO question nahm ich den Code ein Imperativ Schleife gegen Endrekursion zu überprüfen:langsamen Bytecode mit Endrekursion

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()); 

Für Bytecode und nativen Code die Ergebnisse sind

[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 

Die Frage ist: Was ist der Grund für die große Differenz 20 bis 12 Sekunden Ausführungszeit?

bearbeiten, mein Fazit:

Ein Funktionsaufruf apply (in Byte-Code), um eine Stapelgröße zu überprüfen, mögliche Stapel Erweiterung beinhaltet, und einen Scheck für Signale. Für maximale Leistung liefert der native Code Compiler.

(Randbemerkung:. Fragen hier auf SO, weil sie suchmaschinenfreundlich ist)

+1

opt in ocamlopt steht für optimiert. Der Bytecode-Compiler führt weniger Optimierungen durch, da er nie seinen Zweck erfüllt. Obwohl viele Optimierungen noch gemacht werden. Und zum Beispiel bei der aktuellen Version des Compilers (4.03) beträgt der Unterschied etwa 10% (9,3 gegenüber 8,3 Sekunden). – ivg

Antwort

4

Blick auf die Ausgabe von 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))) 

So offensichtlich ist assign schneller als apply. Es scheint Überprüfungen auf Stapelüberläufe und Signale bei Funktionsaufrufen zu geben, aber nicht für eine einfache Zuweisung. Für Details, müssen Sie sich ansehen: https://github.com/ocaml/ocaml/blob/trunk/byterun/interp.c

+0

Okay, habe es gefunden. Das sieht nach einem Forth-Interpreter aus. –