Hi Atamert,
Here's a gist with the example code:
https://gist.github.com/neapel/4e502a14e3738b709672
I tried replacing a closure with a dynamically built and evaluated
>> metafunction but discovered that it was actually slower.
>>
>
> If evaluating code during run is slower than AOT compiling it, it wouldn't
> surprise me.
>
I didn't actually try AOT compiling it, just using the REPL. As far as I
understand there shouldn't be a difference in speed, since (eval) runs the
same compiler as AOT does, and even writes out a .class file.
(possibly unrelated, maybe due to eval, when trying to AOT compile the
example project by adding `:aot :all` and running `lein jar`, it appears to
fall into an infinite loop. The JAR file grew to 8GB, but I couldn't list
its contents.)
> I guess f2 runs this much slower than f1 because it doesn't actually pass
>> a reference to x when unquoting, but clones the value, which means it needs
>> to compare the lists element-wise.
>>
>
> This is interesting. Were you able to confirm it or are you just guessing?
> (I'm just curious.)
>
The code in the Gist produces a nice table now, here's my result (I
couldn't reproduce the case where f3 runs as fast as f1 for vectors; but
it's actually less weird this way)
I think it's quite obvious that f1 compares always references, as does the
"nil" case, while the "vec" and "map" cases compare by value:
| map | vec | nil | name |
|--------+--------+------+------|
| 5 ns | 5 ns | 5 ns | f1 |
| 558 ns | 134 ns | 6 ns | f2 |
| 567 ns | 130 ns | 7 ns | f3 |
| 561 ns | 117 ns | 7 ns | f4 |
It also dumps the disassembly, we can see that:
f1-map == f1-vec == f1-nil (makes sense, as the reference to the value is
passed in the constructor of the closure)
f2-map = f3-map, f2-vec = f3-vec, f2-nil = f3-nil (with renaming)
f4-map = f1, f4-vec = f1, f4-nil = f1 (with renaming)
f2-map = f2-vec, except for calling clojure.lang.RT.map / vector.
So there are only three versions of the actual bytecode:
- the closure f1/f4;
- f2 building a new object in its static constructor
- f2-nil using a null constant instead of a field containing null.
importantly, f1/f4 are identical:
public final class F extends clojure.lang.AFunction {
/* ... static constructor getting clojure.core/= ... */
Object x;
public F(Object o) { x = o }
public Object invoke( Object y ) {
/*basically*/ return (bool (= x y))
}
}
So why does f4 behave almost like f2/f3?!
Cheers,
--
pascal
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.