This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-04-09
Channels
- # beginners (108)
- # boot (14)
- # cider (8)
- # clara (13)
- # cljs-dev (63)
- # cljsrn (5)
- # clojure (57)
- # clojure-brasil (1)
- # clojure-italy (69)
- # clojure-losangeles (10)
- # clojure-nl (6)
- # clojure-poland (2)
- # clojure-spec (6)
- # clojure-uk (50)
- # clojurescript (116)
- # core-async (1)
- # cursive (9)
- # data-science (8)
- # datascript (4)
- # datomic (43)
- # duct (2)
- # editors (1)
- # fulcro (29)
- # instaparse (7)
- # jobs (6)
- # keechma (3)
- # mount (16)
- # off-topic (61)
- # om (10)
- # onyx (5)
- # parinfer (17)
- # pedestal (2)
- # portkey (5)
- # quil (2)
- # re-frame (84)
- # reagent (9)
- # remote-jobs (2)
- # ring-swagger (2)
- # shadow-cljs (17)
- # slack-help (1)
- # tools-deps (29)
- # vim (23)
Direct linking peggiora le performance? Mi aspetterei l'esatto contrario da questi 2 bytecodes https://gist.github.com/reborg/2e60268d87c12e73e9460593f6440276 L'unica cosa che mi viene in mente e' se i call sites di quella funzione sono ottimizzati da hotspot durante il boot di Clojure e poi si rivelano non ottimali. Secondo: sbaglio i bench.
telchi': https://github.com/reborg/euroclojure-2014/blob/master/clojure-beasts-euroclj-2014.pdf (e se ci tieni al faccione parlante, https://vimeo.com/100518965)
Essi', 90% sara' sicuramente quello. In sintesi:
1. cambio 2 linee in https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L2744-L2745 con (.reduce (fn [b x] (chunk-append b (f x)) b)
2. mvn clean; mvn -Dmaven.test.skip=true install
produce nuovo jar $M2_REPO/org/clojure/clojure/1.10.0-master-SNAPSHOT/clojure-1.10.0-master-SNAPSHOT.jar
3. faccio partire REPL con jar appena creato, aggiungendo criterium al classpath
4. eseguo bench tipo (let [lr (range 100000)] (bench (doall (map inc lr))))
5. Creo (defn map* [f coll])
funzione locale con la stessa modifica di quella in core, ma solo arity-2 con la modifica, non il resto.
6. Eseguo stesso bench: 40% piu' veloce.
@reborg intuitivamente, fare multipli benchmark sulla stessa jvm non e` una grande idea
Sembra the tu abbia ragione @bronsa, se tutte le volte ristarto la VM e bencho una cosa alla volta. Probabilmente poi ho confuso il tutto senza rendermene conto. Lavoro ingrato se ho una 50 di bench da runnare!
ehm, pero' il risultato e' lo stesso: codice nuovo in core 3.77ms, stesso codice eval in REPL 3.25ms
Grazie, sempre utile avere il tuo risconstro. Anche perche' ci vorrei andare a fondo e capire se c'e' uno sbaglio o che.
per escludere sta cosa delle arity, JITando esattamente la funzione identica i benchmark cambiano?
inoltre sarebbe interessante benchmarkare su una versione AOT ma non direct linked in questo caso
se hai tempo ti consiglerei di fare ste prove per vedere dove entra in gioco la varianza
Allora: clj-head con modifica: 3.22ms copia REPL con modifica solo arity-2 REPL: 2.74ms copia REPL con modifica arity originali: 2.79ms Quindi no arity... andiamo di noDL: clj-head con modifica no DL: 3.65ms copia REPL con modifica solo arity-2 REPL no DL: 2.87ms copia REPL con modifica arity originali no DL: 2.88ms Quindi eliminiamo anche il fattore direct linking (che giustamente sembra peggiorare la cosa). Probabilmente ci sono altri fattori in gioco. Almeno ora so che evitare il compare versioni appena compilate e quello che viene dal jar.
che si deve scannare tutta la in memory cache prima di fallbackare su disco quando la funziona e` AOTd
potrebbe esserci un’ottimizzazione per DynamicClassLoader da fare fosse quello il caso
static Class<?> findInMemoryClass(String name) {
Reference<Class> cr = classCache.get(name);
if(cr != null)
{
Class c = cr.get();
if(c != null)
return c;
else
classCache.remove(name, cr);
}
return null;
}
protected Class<?>findClass(String name) throws ClassNotFoundException {
Class c = findInMemoryClass(name);
if (c != null)
return c;
else
return super.findClass(name);
}
ma il lookup devi farlo comunque e prima di poterlo fare se e` AOT, hai una cache miss sulla cache in memory
protected Class<?>findClass(String name) throws ClassNotFoundException {
Class c = findInMemoryClass(name);
if (c == null) {
c = super.findClass(name);
if (c != null)
classCache.put(name, new SoftReference (c, rq));
}
return c;
}
possibile che ci siano altri fattori in gioco ma intuitivamente questo e` l’unico che mi viene in mente
no, c'è un altra cache nell'urlclassloader ma che viene hittata solo dopo una miss a quella di dynamicclassloader
@reborg che strada consigli di seguire per esplorare il codice di clojure? (btw molto interessante il talk, grazie per averlo tenuto e per avermi condiviso il link) se hai links o pdf da condividere sarei molto interessato
@gabriele.carrettoni Personalmente ho trovato utile caricarlo su IntelliJ e cominciare ad andare in giro al codice, ad esempio come nel video prendendo una form e seguendone l'evaluation coi breakpoints in debug. Putroppo non c'e' una guida agli internals ma tante persone che nel tempo si sono cimentate nell'impresa e ne hanno tirato fuori blogs e presentazioni.
questo e' un talk simile: https://www.youtube.com/watch?v=6DaBmz_6y0s
@gabriele.carrettoni sottoscrivo al consiglio di renzo, apriti una repl, attaccati un debugger, metti breakpoint su clojure.lang.Compiler.*
/`Clojure.lang.LispReader.*`, evalua prima 1
, poi (+ 1 2)
, poi (fn [x] (+ 1 x))
e segui l’evaluation
e non fare come me che da idiota s’e` imparato tutto seguendo a mano il sorgente invece di usare un debugger ;)
non imparerai tutti i dettagli di come e` implementato clojure in questo modo, ma ti farai una buona idea di come funzioni
l’alternativa se sei un masochista come me, apriti clojure.lang.RT
e inizia a leggere sequenzialmente, seguendo tutte le reference