|
View:
New views
20 Messages
—
Rating Filter:
Alert me
|
| < Prev | 1 - 2 | Next > |
|
|
Thoughts about RichObjects, Implicit convertions and performanceOne of the typical uses of implicit conversions is to declare
"additional" methods for the existing class. Compiler substitutes reference to object with invocation of implicit function that typically instantiates some kind of RichObject or anonymous object with additional functions. For example var i = 5; i = i max 6; i = i max 7; will be compiled to 2 instantiations of RichInt. The use of anonymous declaration in implicit will cause big performance degradation. Also in these cases usually impossible to reuse created instance. The idea is to create some kind of "implicit traits" for this kind of situations that would not cause performance issues and also eliminates the need of implicit def declarations: implicit[Int] trait RichInt { def max(x: Int) = this > x def min(x: Int) = this < x } and the i = i max 6; will actually be compiled to "static" method invocation i = RichInt.max(i, 6); The performance difference is significant object XT { implicit def int2x(i: Int) = new { def sum(x: Int) = i + x } def sum(i:Int, x:Int) = i + x; def main(args : Array[String]) = { //simple val iterations = 10000000 var start = System.currentTimeMillis var i=0; var x=0; while(i < iterations) { x = x sum i sum i; i = i + 1; } println(x + " in " + (System.currentTimeMillis - start) ); //fast start = System.currentTimeMillis i=0; x=0; while(i < iterations) { x = sum(sum(x, i),i); i = i + 1; } println(x + " in " + (System.currentTimeMillis - start) ); } } ============= 266447232 in 7557 266447232 in 20 -- Best Regards, Vladimir Kirichenko |
|
|
Re: Thoughts about RichObjects, Implicit convertions and performanceStructural subtyping (your new {} in int2x) uses reflection for
invocations. That's your first performance problem. Use a trait like this: trait SummingInt{ def sum(x:Int):Int } implicit def int2x(i: Int) = new SummingInt{ def sum(x: Int) = i + x } And performances will be much better: 266447232 in 324 266447232 in 23 266447232 in 241 266447232 in 13 266447232 in 245 266447232 in 15 266447232 in 239 266447232 in 15 266447232 in 251 266447232 in 17 266447232 in 229 266447232 in 15 266447232 in 235 266447232 in 15 266447232 in 228 266447232 in 15 266447232 in 233 266447232 in 15 266447232 in 222 266447232 in 15 In the end performance is still 10 times worse. Your example stresses the cost of boxing primitives. It wouldn't be as bad if you would do the same with objects (relative to the actual calculation done). If you want to get the best performance you will have to optimize tight loops anyway, so you would probably refrain from using implicits in this case. Johannes ----------------------------------------------- Johannes Rudolph http://virtual-void.net On Tue, Mar 24, 2009 at 5:23 AM, Vladimir Kirichenko <vladimir.kirichenko@...> wrote: > object XT { > > implicit def int2x(i: Int) = new { > def sum(x: Int) = i + x > } > > def sum(i:Int, x:Int) = i + x; > > def main(args : Array[String]) = { > > //simple > val iterations = 10000000 > var start = System.currentTimeMillis > > var i=0; > var x=0; > > while(i < iterations) { > x = x sum i sum i; > i = i + 1; > } > > println(x + " in " + (System.currentTimeMillis - start) ); > > //fast > start = System.currentTimeMillis > > i=0; > x=0; > > while(i < iterations) { > x = sum(sum(x, i),i); > i = i + 1; > } > > println(x + " in " + (System.currentTimeMillis - start) ); > > } > } |
|
|
Re: Thoughts about RichObjects, Implicit convertions and performanceOn Mon, Mar 23, 2009 at 9:23 PM, Vladimir Kirichenko
<vladimir.kirichenko@...> wrote: > One of the typical uses of implicit conversions is to declare > "additional" methods for the existing class. Compiler substitutes > reference to object with invocation of implicit function that typically > instantiates some kind of RichObject or anonymous object with additional > functions. For example > > var i = 5; > i = i max 6; > i = i max 7; > > will be compiled to 2 instantiations of RichInt. The use of anonymous > declaration in implicit will cause big performance degradation. > > Also in these cases usually impossible to reuse created instance. > > The idea is to create some kind of "implicit traits" for this kind of > situations that would not cause performance issues and also eliminates > the need of implicit def declarations: > > implicit[Int] trait RichInt { > def max(x: Int) = this > x > def min(x: Int) = this < x > } > > and the > > i = i max 6; > > will actually be compiled to "static" method invocation > > i = RichInt.max(i, 6); A similar idea has been proposed along these lines before (albeit with a different syntax), and I think it would be great to have something like this. Someone--you? :-)--should spearhead a SIP for it. First observation: I personally would prefer the syntax implicit class RichInt(i: Int) { def max(o: Int) = if (i >= o) i else o } with the same semantics you propose, but that's mainly because I feel icky about "this" pointing to something other than, well, "this". Second observation, your benchmarking (below) is the "wrong" way to benchmark JVM code because of the peculiarities of hotspot. You should wrap these calls in a method and call it at least 10,000 times in a method before clocking speeds. HotSpot can do amazing things when you give it a chance. That said, my understanding* is that HotSpot does not (yet**) do a great job removing object creations, which is what is needed to really make implicits faster. -- David * which could be wrong. ** see http://blog.juma.me.uk/2008/12/17/objects-with-no-allocation-overhead/ > > The performance difference is significant > > object XT { > > implicit def int2x(i: Int) = new { > def sum(x: Int) = i + x > } > > def sum(i:Int, x:Int) = i + x; > > def main(args : Array[String]) = { > > //simple > val iterations = 10000000 > var start = System.currentTimeMillis > > var i=0; > var x=0; > > while(i < iterations) { > x = x sum i sum i; > i = i + 1; > } > > println(x + " in " + (System.currentTimeMillis - start) ); > > //fast > start = System.currentTimeMillis > > i=0; > x=0; > > while(i < iterations) { > x = sum(sum(x, i),i); > i = i + 1; > } > > println(x + " in " + (System.currentTimeMillis - start) ); > > } > } > ============= > 266447232 in 7557 > 266447232 in 20 > > > > -- > Best Regards, > Vladimir Kirichenko > > |
|
|
Re: Thoughts about RichObjects, Implicit convertions and performanceOn Tue, Mar 24, 2009 at 7:23 AM, David Hall <dlwh@...> wrote:
> Second observation, your benchmarking (below) is the "wrong" way to > benchmark JVM code because of the peculiarities of hotspot. You should > wrap these calls in a method and call it at least 10,000 times in a > method before clocking speeds. HotSpot can do amazing things when you > give it a chance. > > That said, my understanding* is that HotSpot does not (yet**) do a > great job removing object creations, which is what is needed to really > make implicits faster. Right, see http://wikis.sun.com/display/HotSpotInternals/MicroBenchmarks for some tips how to fix microbenchmarks with the Hotspot compiler of the OpenJDK. You can use -XX:+PrintCompilation VM option (with OpenJDK or Sun JVM) to see when methods get JIT-compiled. In this particular case my tries showed, that the method is compiled just after (while?) the first run, so doing 10 iterations of the whole method should suffice. Johannes ----------------------------------------------- Johannes Rudolph http://virtual-void.net |
|
|
Re: Thoughts about RichObjects, Implicit convertions and performanceI'd like:
object MyImplicits { //Syntax // implicit[targetType] def methodName[type params](params) : returnType = { expr } //i.e implicit[String] def isAllDigits = this.matches("^\\d+$") implicit[Z <: AnyRef] def asInstanceOf[T](implicit clasz : Manifest[T]) : clasz.cast(this) } //usage: import MyImplicits._ "0000".isAllDigits 5.asInstanceOf[Fajita] //Yes, this example is the very definition of WTF On Tue, Mar 24, 2009 at 7:42 AM, Johannes Rudolph <johannes.rudolph@...> wrote:
-- Viktor Klang Senior Systems Analyst |
|
|
Re: Thoughts about RichObjects, Implicit convertions and performanceIMHO it would make more sense to allow an "inversion" of the first element of a parameterlist in order to preserve performance, like in the Nice language: [code] //pseudocode inversion def max(x:Int, y:Int) = if (x > y) x else y val m = 10.max(20) //or using the infix notation val m = 10 max 20 [/code] |
|
|
Re: Thoughts about RichObjects, Implicit convertions and performanceOn Tue, Mar 24, 2009 at 9:36 AM, Viktor Klang <viktor.klang@...> wrote: I'd like: implicit[Z <: AnyVal] def asInstanceOf[T](implicit clasz : Manifest[T]) : clasz.cast(this)
-- Viktor Klang Senior Systems Analyst |
|
|
Re: Thoughts about RichObjects, Implicit convertions and performanceIf this language addition is to be considered I would very much prefer a
C# extension method syntax: def newStringMethod(this str : String)(arg1 : T1, arg2 : T2) = ... Note the use of the "this" keyword on the first parameter. /Jesper Nordenberg Viktor Klang wrote: > > > On Tue, Mar 24, 2009 at 9:36 AM, Viktor Klang <viktor.klang@... > <mailto:viktor.klang@...>> wrote: > > I'd like: > > object MyImplicits > { > //Syntax > // implicit[targetType] def methodName[type params](params) : > returnType = { expr } > > > //i.e > implicit[String] def isAllDigits = this.matches("^\\d+$") > > implicit[Z <: AnyRef] def asInstanceOf[T](implicit clasz : > Manifest[T]) : clasz.cast(this) > > > implicit[Z <: Any*Val*] def asInstanceOf[T](implicit clasz : > Manifest[T]) : clasz.cast(this) > > > > } > > //usage: > > import MyImplicits._ > > "0000".isAllDigits > > 5.asInstanceOf[Fajita] //Yes, this example is the very definition of WTF > > > On Tue, Mar 24, 2009 at 7:42 AM, Johannes Rudolph > <johannes.rudolph@... > <mailto:johannes.rudolph@...>> wrote: > > On Tue, Mar 24, 2009 at 7:23 AM, David Hall > <dlwh@... <mailto:dlwh@...>> wrote: > > Second observation, your benchmarking (below) is the "wrong" > way to > > benchmark JVM code because of the peculiarities of hotspot. > You should > > wrap these calls in a method and call it at least 10,000 > times in a > > method before clocking speeds. HotSpot can do amazing things > when you > > give it a chance. > > > > That said, my understanding* is that HotSpot does not (yet**) > do a > > great job removing object creations, which is what is needed > to really > > make implicits faster. > > Right, see > http://wikis.sun.com/display/HotSpotInternals/MicroBenchmarks > for some tips how to fix microbenchmarks with the Hotspot > compiler of > the OpenJDK. You can use -XX:+PrintCompilation VM option (with > OpenJDK > or Sun JVM) to see when methods get JIT-compiled. In this particular > case my tries showed, that the method is compiled just after > (while?) > the first run, so doing 10 iterations of the whole method should > suffice. > > Johannes > > ----------------------------------------------- > Johannes Rudolph > http://virtual-void.net > > > > > -- > Viktor Klang > Senior Systems Analyst > > > > > -- > Viktor Klang > Senior Systems Analyst |
|
|
Re: Re: Thoughts about RichObjects, Implicit convertions and performanceHow about keeping the syntax we have but in those limited cases making
it equivalent in bytecode to C#'s extension methods? 2009/3/24 Jesper Nordenberg <megagurka@...>: > If this language addition is to be considered I would very much prefer a C# > extension method syntax: > > def newStringMethod(this str : String)(arg1 : T1, arg2 : T2) = ... > > Note the use of the "this" keyword on the first parameter. > > /Jesper Nordenberg > > Viktor Klang wrote: >> >> >> On Tue, Mar 24, 2009 at 9:36 AM, Viktor Klang <viktor.klang@... >> <mailto:viktor.klang@...>> wrote: >> >> I'd like: >> >> object MyImplicits >> { >> //Syntax >> // implicit[targetType] def methodName[type params](params) : >> returnType = { expr } >> >> >> //i.e >> implicit[String] def isAllDigits = this.matches("^\\d+$") >> >> implicit[Z <: AnyRef] def asInstanceOf[T](implicit clasz : >> Manifest[T]) : clasz.cast(this) >> >> >> implicit[Z <: Any*Val*] def asInstanceOf[T](implicit clasz : Manifest[T]) >> : clasz.cast(this) >> >> >> } >> >> //usage: >> >> import MyImplicits._ >> >> "0000".isAllDigits >> >> 5.asInstanceOf[Fajita] //Yes, this example is the very definition of >> WTF >> >> >> On Tue, Mar 24, 2009 at 7:42 AM, Johannes Rudolph >> <johannes.rudolph@... >> <mailto:johannes.rudolph@...>> wrote: >> >> On Tue, Mar 24, 2009 at 7:23 AM, David Hall >> <dlwh@... <mailto:dlwh@...>> wrote: >> > Second observation, your benchmarking (below) is the "wrong" >> way to >> > benchmark JVM code because of the peculiarities of hotspot. >> You should >> > wrap these calls in a method and call it at least 10,000 >> times in a >> > method before clocking speeds. HotSpot can do amazing things >> when you >> > give it a chance. >> > >> > That said, my understanding* is that HotSpot does not (yet**) >> do a >> > great job removing object creations, which is what is needed >> to really >> > make implicits faster. >> >> Right, see >> http://wikis.sun.com/display/HotSpotInternals/MicroBenchmarks >> for some tips how to fix microbenchmarks with the Hotspot >> compiler of >> the OpenJDK. You can use -XX:+PrintCompilation VM option (with >> OpenJDK >> or Sun JVM) to see when methods get JIT-compiled. In this >> particular >> case my tries showed, that the method is compiled just after >> (while?) >> the first run, so doing 10 iterations of the whole method should >> suffice. >> >> Johannes >> >> ----------------------------------------------- >> Johannes Rudolph >> http://virtual-void.net >> >> >> >> >> -- Viktor Klang >> Senior Systems Analyst >> >> >> >> >> -- >> Viktor Klang >> Senior Systems Analyst > > |
|
|
Re: Thoughts about RichObjects, Implicit convertions and performanceDavid Hall <dlwh <at> cs.stanford.edu> writes:
> That said, my understanding* is that HotSpot does not (yet**) do a > great job removing object creations, which is what is needed to really > make implicits faster. Certainly not by default, but as it was shown in that blog entry it does well (but not yet great) once you enable Escape Analysis in the right JDK version. The good news is that JDK 6 Update 14 (currently available as an early access release) is one of these. Also, from the discussion in the comments, one can imagine that the performance gap between no allocation and allocation that is optimised away may go away in the future. Furthermore, in many real-world scenarios I would guess that there's no difference as it is (not all code can benefit from aggressive loop unrolling as the benchmark in the blog entry does). Best, Ismael |
|
|
Re: Re: Thoughts about RichObjects, Implicit convertions and performanceOn Tue, Mar 24, 2009 at 10:15 AM, Jesper Nordenberg <megagurka@...> wrote: If this language addition is to be considered I would very much prefer a C# extension method syntax: Why not keep it simple: implicit def newStringMethod(this : String)(args) = ... "this" is valid as parameter name if, and only if it's the only parameter in the first parameter clause of an implicit method. Then the compiler can mangle "this" into "implicit_this" as to not accidentally collide with anything. It can be expanded to the equivalent Java code: <scope> static <returnType> <methodname>(<thistype> implicit_this, <params>) <body>
-- Viktor Klang Senior Systems Analyst |
|
|
Re: Thoughts about RichObjects, Implicit convertions and performance> And performances will be much better:
> 266447232 in 324 > 266447232 in 23 Yes but not so better. Here is more correct benchmark: object XT { implicit def int2x(i: Int) = new { def sum(x: Int) = i + x } def sum(i:Int, x:Int) = i + x; trait SummingInt{ def xsum(x:Int):Int } implicit def int2xx(i: Int) = new SummingInt { def xsum(x: Int) = i + x } def withReflect(times: Int):Long = { var start = System.currentTimeMillis var i=0; var x=0; while(i < times) { x = x sum i sum i sum i sum i; i = i + 1; } System.currentTimeMillis - start } def withTrait(times: Int):Long = { var start = System.currentTimeMillis var i=0; var x=0; while(i < times) { x = x xsum i xsum i xsum i xsum i; i = i + 1; } System.currentTimeMillis - start } def withCall(times: Int):Long = { val start = System.currentTimeMillis var i=0; var x=0; while(i < times) { x = sum(sum(sum(sum(x, i),i),i),i); i = i + 1; } System.currentTimeMillis - start; } def main(args : Array[String]) = { val iterations = 100000000 //heating it up withReflect(iterations); withTrait(iterations); withCall(iterations); val ronce = withReflect(1); val rtimes = withReflect(iterations); val tonce = withTrait(1); val ttimes = withTrait(iterations); val conce = withCall(1); val ctimes = withCall(iterations); println("reflect: " + (rtimes - ronce)) println("trait: " + (ttimes - tonce)) println("call: " + (ctimes - conce)) } ================= reflect: 102842 trait: 3884 call: 0 Difference is significant and still there. -- Best Regards, Vladimir Kirichenko |
|
|
Re: Thoughts about RichObjects, Implicit convertions and performanceNot to be snarky about this, but I'm pretty sure that all these benchmarks will report incorrect numbers. HotSpot does analysis on what is done inside of loops and will remove calculations of values that are not accessed when the loop is done (this actually depends on what version of JVM you're using, what your processor is, and if you're in client or server mode.) Further, HotSpot may do loop unrolling.
So, I'm not sure one can accurately benchmark the differences between the variations on adding 1 to a subsequently discarded Int without running into these optimizations. :-(
On Tue, Mar 24, 2009 at 7:10 AM, Vladimir Kirichenko <vladimir.kirichenko@...> wrote:
-- Lift, the simply functional web framework http://liftweb.net Beginning Scala http://www.apress.com/book/view/1430219890 Follow me: http://twitter.com/dpp Git some: http://github.com/dpp |
|
|
Re: Thoughts about RichObjects, Implicit convertions and performanceoops, my bad, whole loop eliminated:). this one is better:
object XT { implicit def int2x(i: Int) = new { def sum(x: Int) = i + x } def sum(i:Int, x:Int) = i + x; trait SummingInt{ def xsum(x:Int):Int } implicit def int2xx(i: Int) = new SummingInt { def xsum(x: Int) = i + x } def withReflect(times: Int) = { var start = System.currentTimeMillis var i=0; var x=0; while(i < times) { x = x sum i sum i sum i sum i; i = i + 1; } (System.currentTimeMillis - start, x); } def withTrait(times: Int) = { var start = System.currentTimeMillis var i=0; var x=0; while(i < times) { x = x xsum i xsum i xsum i xsum i; i = i + 1; } (System.currentTimeMillis - start, x); } def withCall(times: Int) = { val start = System.currentTimeMillis var i=0; var x=0; while(i < times) { x = sum(sum(sum(sum(x, i),i),i),i); i = i + 1; } (System.currentTimeMillis - start, x); } def main(args : Array[String]) = { //simple val iterations = 100000000 //heating it up withReflect(iterations); withTrait(iterations); withCall(iterations); val ronce = withReflect(1); val rtimes = withReflect(iterations); val tonce = withTrait(1); val ttimes = withTrait(iterations); val conce = withCall(1); val ctimes = withCall(iterations); println(rtimes._2 + " reflect: " + (rtimes._1 - ronce._1)) println(ttimes._2 + " trait: " + (ttimes._1 - tonce._1)) println(ctimes._2 + " call: " + (ctimes._1 - conce._1)) } } ================= -745128448 reflect: 100911 -745128448 trait: 3835 -745128448 call: 163 -- Best Regards, Vladimir Kirichenko |
|
|
Re: Thoughts about RichObjects, Implicit convertions and performance> First observation: I personally would prefer the syntax
> > implicit class RichInt(i: Int) { > def max(o: Int) = if (i >= o) i else o > } In the class-case there supposed to be some x instanceof ThatClass. There will not be such case. I proposed trait because it's behavioristic extensions. -- Best Regards, Vladimir Kirichenko |
|
|
Re: Re: Thoughts about RichObjects, Implicit convertions and performanceOn Tue, Mar 24, 2009 at 11:17 AM, Ricky Clarkson
<ricky.clarkson@...> wrote: > How about keeping the syntax we have but in those limited cases making > it equivalent in bytecode to C#'s extension methods? Thats much better. S# style declaration conflict with scala "curring" declarations. -- Best Regards, Vladimir Kirichenko |
|
|
Re: Re: Thoughts about RichObjects, Implicit convertions and performancePlease could you rephrase that, or could someone else please explain it to me?
2009/3/24 Vladimir Kirichenko <vladimir.kirichenko@...>: > On Tue, Mar 24, 2009 at 11:17 AM, Ricky Clarkson > <ricky.clarkson@...> wrote: >> How about keeping the syntax we have but in those limited cases making >> it equivalent in bytecode to C#'s extension methods? > > Thats much better. S# style declaration conflict with scala "curring" > declarations. > -- > Best Regards, > Vladimir Kirichenko > |
|
|
Re: Re: Thoughts about RichObjects, Implicit convertions and performanceI meant that C#-like extension methods:
void method(this str:Sring)(x:Int) looks ok for C# where could be the only parameter set but in scala it will clash with multiple parameter sets def method(x:Int)(y:Int)(z:Int) =.. On Tue, Mar 24, 2009 at 4:52 PM, Ricky Clarkson <ricky.clarkson@...> wrote: > Please could you rephrase that, or could someone else please explain it to me? -- Best Regards, Vladimir Kirichenko |
|
|
Re: Thoughts about RichObjects, Implicit convertions and performanceOn Tue, Mar 24, 2009 at 4:48 PM, Vladimir Kirichenko
<vladimir.kirichenko@...> wrote: >> First observation: I personally would prefer the syntax >> >> implicit class RichInt(i: Int) { >> def max(o: Int) = if (i >= o) i else o >> } > > In the class-case there supposed to be some x instanceof ThatClass. > There will not be such case. I proposed trait because it's > behavioristic extensions. oops, wrong again:)) class X(i:Int) { def dbl = i * 2 } implicit def i2x(i:Int) = new X(i) def f(x:X) = x.dbl f(10) Class is better than trait. -- Best Regards, Vladimir Kirichenko |
|
|
Re: Re: Thoughts about RichObjects, Implicit convertions and performanceOn Tue, Mar 24, 2009 at 2:17 AM, Ricky Clarkson
<ricky.clarkson@...> wrote: > How about keeping the syntax we have but in those limited cases making > it equivalent in bytecode to C#'s extension methods? The reason I would push for new syntax--and in particular my new syntax-- is because implicits are commonly used to implement a type class pattern as well as for extension methods. For instance: trait Ordered[T] { def compare(t:T) : Int // ... // ... } implicit def orderedInt(x: Int) = new OrderedInt(x); class OrderedInt(x: Int) extends Ordered[T] { def compare(t: Int) = // ... } (You can inline this simple example, but sometimes you can't.) Under either Vladimir's or my syntax, you could change this to be: implicit class OrderedInt(x: Int) extends Ordered[Int] { def compare(t: Int) = // ... } You could then imagine the compiler emitting two classes, OrderedInt and OrderedInt$, with the latter providing static methods and the former being the "usual" type class pattern as we have it today. -- David |
| < Prev | 1 - 2 | Next > |
| Free embeddable forum powered by Nabble | Forum Help |