Ho del codice Clojure che simula e quindi elabora dati numerici. I dati sono fondamentalmente vettori di valori doppi; l'elaborazione coinvolge principalmente la somma dei loro valori in vari modi. Includerò del codice qui sotto, ma la mia domanda è (penso) più generale - semplicemente non ho la minima idea di come interpretare i risultati dell'hprof.Per favore aiutami a capire queste tracce di Hclof Clojure
Comunque, il mio codice di prova è:
(defn spin [n]
(let [c 6000
signals (spin-signals c)]
(doseq [_ (range n)] (time (spin-voxels c signals)))))
(defn -main []
(spin 4))
dove spin-voxels
dovrebbe essere più costoso di spin-signals
(soprattutto se ripetuta più volte). Posso dare le routine di livello inferiore, ma penso che questa domanda riguardi di più il fatto che non capisco le basi delle tracce (sotto).
Quando compilo questo con Lein e poi fare qualche semplice profiling:
> java -cp classes:lib/clojure-1.3.0-beta1.jar -agentlib:hprof=cpu=samples,depth=10,file=hprof.vec com.isti.compset.stack
"Elapsed time: 14118.772924 msecs"
"Elapsed time: 10082.015672 msecs"
"Elapsed time: 9212.522973 msecs"
"Elapsed time: 12968.23877 msecs"
Dumping CPU usage by sampling running threads ... done.
e la traccia del profilo assomiglia:
CPU SAMPLES BEGIN (total = 4300) Sun Aug 28 15:51:40 2011
rank self accum count trace method
1 5.33% 5.33% 229 300791 clojure.core$seq.invoke
2 5.21% 10.53% 224 300786 clojure.core$seq.invoke
3 5.05% 15.58% 217 300750 clojure.core$seq.invoke
4 4.93% 20.51% 212 300787 clojure.lang.Numbers.add
5 4.74% 25.26% 204 300799 clojure.core$seq.invoke
6 2.60% 27.86% 112 300783 clojure.lang.RT.more
7 2.51% 30.37% 108 300803 clojure.lang.Numbers.multiply
8 2.42% 32.79% 104 300788 clojure.lang.RT.first
9 2.37% 35.16% 102 300831 clojure.lang.RT.more
10 2.37% 37.53% 102 300840 clojure.lang.Numbers.add
che è piuttosto fresco. Fino a qui, sono felice. Vedo che sto perdendo tempo con la gestione generica dei valori numerici.
Così guardo il mio codice e decido che, come primo passo, mi sostituisco vec
con d-vec
:
(defn d-vec [collection]
(apply conj (vector-of :double) collection))
non sono sicuro che sarà sufficiente - Ho il sospetto che sarà anche bisogno di aggiungere alcune annotazioni di tipo in vari punti - ma sembra un buon inizio. Quindi compilo e profilo di nuovo:
> java -cp classes:lib/clojure-1.3.0-beta1.jar -agentlib:hprof=cpu=samples,depth=10,file=hprof.d-vec com.isti.compset.stack
"Elapsed time: 15944.278043 msecs"
"Elapsed time: 15608.099677 msecs"
"Elapsed time: 16561.659408 msecs"
"Elapsed time: 15416.414548 msecs"
Dumping CPU usage by sampling running threads ... done.
Ewww. Quindi è molto più lento. E il profilo?
CPU SAMPLES BEGIN (total = 6425) Sun Aug 28 15:55:12 2011
rank self accum count trace method
1 26.16% 26.16% 1681 300615 clojure.core.Vec.count
2 23.28% 49.45% 1496 300607 clojure.core.Vec.count
3 7.74% 57.18% 497 300608 clojure.lang.RT.seqFrom
4 5.59% 62.77% 359 300662 clojure.core.Vec.count
5 3.72% 66.49% 239 300604 clojure.lang.RT.first
6 3.25% 69.74% 209 300639 clojure.core.Vec.count
7 1.91% 71.66% 123 300635 clojure.core.Vec.count
8 1.03% 72.68% 66 300663 clojure.core.Vec.count
9 1.00% 73.68% 64 300644 clojure.lang.RT.more
10 0.79% 74.47% 51 300666 clojure.lang.RT.first
11 0.75% 75.22% 48 300352 clojure.lang.Numbers.double_array
12 0.75% 75.97% 48 300638 clojure.lang.RT.more
13 0.64% 76.61% 41 300621 clojure.core.Vec.count
14 0.62% 77.23% 40 300631 clojure.core.Vec.cons
15 0.61% 77.84% 39 300025 java.lang.ClassLoader.defineClass1
16 0.59% 78.43% 38 300670 clojure.core.Vec.cons
17 0.58% 79.00% 37 300681 clojure.core.Vec.cons
18 0.54% 79.55% 35 300633 clojure.lang.Numbers.multiply
19 0.48% 80.03% 31 300671 clojure.lang.RT.seqFrom
20 0.47% 80.50% 30 300609 clojure.lang.Numbers.add
Ho incluso più righe qui perché questa è la parte che non capisco.
Perché su terra è Vec.count
visualizzato così spesso? È un metodo che restituisce la dimensione del vettore. Una singola linea di ricerca di un attributo.
Suppongo di essere più lento perché sto ancora saltando avanti e indietro tra Double e Double, e che le cose potrebbero migliorare ancora quando aggiungo più annotazioni di tipo. Ma non capisco quello che ho adesso, quindi non sono così sicuro che fungere da sbalordimento abbia molto senso.
Per favore, qualcuno può spiegare la discarica sopra in termini generali? Prometto di non chiamare ripetutamente lo count
- invece ho un sacco di mappe e riduzioni e alcuni cicli espliciti.
Mi chiedevo se potrei essere confuso dalla JIT? Forse mi manca una pila di informazioni perché le funzioni sono in linea? Oh, e sto usando 1.3.0-beta1 perché sembra avere una gestione dei numeri più ragionevole.
[UPDATE ] ho riassunto le mie esperienze a http://www.acooke.org/cute/Optimising1.html - ha ottenuto un aumento di velocità 5x (in realtà era 10 volte dopo la pulizia un po 'di più e passare alla 1.3), nonostante non capire questo.
'(in (vector-of: double) collection)' può funzionare meglio per d-vec, ed è idiomatico –
ah, grazie. Ho finito per riscriverlo per usare matrici mutevoli come descritto su http://www.acooke.org/cute/Optimising1.html ma potrebbe funzionare al di fuori del ciclo centrale. –
ok, ho provato a sostituire alcuni doppi array che erano immutabili con i doppi vettori usando il tuo suggerimento, ma si scopre che non c'è modo (che io possa trovare) di aggiungere suggerimenti tipo per loro, e senza suggerimenti ricevo avvertimenti dinamici (e codice lento) in cui vengono utilizzati i dati. –