This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Re: Can I get an optimisation?

4 replies
Joshua.Suereth
Joined: 2008-09-02,
User offline. Last seen 32 weeks 6 days ago.
Good to know.  It also makes sense.   I was running through an algorithm to determine if you could optimise the enumeration.   They all rely on the premise that the code with the pattern match would get recompiled after the enumeration changes.  As I've worked in too many projects, I know there will be the case where this doesn't happen and subtle bugs would be introduced.    However, you could potentially make the optimisation available as a -Y option, and emit warnings if the enumeration + switch are in separate compilation units.

In any case, I was just curious if anyone had thought about this, or if it was even useful enough to pay attention to it.

On Sun, Aug 29, 2010 at 1:11 PM, Alex Cruise <alex@cluonflux.com> wrote:
javac only emits a switch opcode when the switch statement is in the same compilation unit (i.e. file) as the enum is declared.  Otherwise you get an if-then-else ladder.
-0xe1a

On Sun, Aug 29, 2010 at 9:52 AM, Josh Suereth <joshua.suereth@gmail.com> wrote:
import annotation.switch

object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
}

import WeekDay._

class Test {
  def couldThisBeOptimised(x : WeekDay) = x match {
    case Mon => "Case of the Mondays"
    case Tue => "Ruby Tuesdays?"
    case Fri => "Thank God!"
    case _ => "Not an interesting day"
  }
}

Just for fun, I tried to see if I could force this by hand:
object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
  val Mon_ID = Mon.id;
  val Tue_ID = Tue.id;
  val Wed_ID = Wed.id;
  val Thu_ID = Thu.id;
  val Fri_ID = Fri.id;
  val Sat_ID = Sat.id;
  val Sun_ID = Sun.id;
}
import WeekDay._
scala> def notOptimisedEnum(x : WeekDay) = (x.id : @switch) match {
     |     case Mon_ID => "Case of the Mondays"
     |     case Tue_ID => "Ruby Tuesdays?"
     |     case Fri_ID => "Thank God!"
     |     case _ => "Not an interesting day"
     |   }
<console>:13: error: could not emit switch for @switch annotated match
       def notOptimisedEnum(x : WeekDay) = (x.id : @switch) match {

So, my question is:  How relevant is emitting a tableswitch bytecode when pattern matching an Enumeration?   This seems like a chalk against Scala enumerations (and for encoding enumerations inside Java).   However, I haven't ever had a tight loop where I had to rely on the tableswitch bytecode for performance before, so I was wondering what everyone else thought here.



Iulian Dragos 2
Joined: 2009-02-10,
User offline. Last seen 42 years 45 weeks ago.
Re: {mailcleaner} Re: Can I get an optimisation?
Unfortunately, this is impossible. A tableswitch requires that the alternatives are statically known, as int values. The weekday object is generating ids at runtime, so the method bytecode would need to be generated reflectively, probably ending up much slower than a bunch of ifs.
For instance, this works:
  final val ONE = 1  final val TWO = 2   final val THREE = 3
  def testOpt2(x: Int) = (x: @switch) match {     case ONE => "a"    case TWO => "b"     case _ => "c"  }
iulian

On Sun, Aug 29, 2010 at 7:16 PM, Josh Suereth <joshua.suereth@gmail.com> wrote:
Good to know.  It also makes sense.   I was running through an algorithm to determine if you could optimise the enumeration.   They all rely on the premise that the code with the pattern match would get recompiled after the enumeration changes.  As I've worked in too many projects, I know there will be the case where this doesn't happen and subtle bugs would be introduced.    However, you could potentially make the optimisation available as a -Y option, and emit warnings if the enumeration + switch are in separate compilation units.

In any case, I was just curious if anyone had thought about this, or if it was even useful enough to pay attention to it.

On Sun, Aug 29, 2010 at 1:11 PM, Alex Cruise <alex@cluonflux.com> wrote:
javac only emits a switch opcode when the switch statement is in the same compilation unit (i.e. file) as the enum is declared.  Otherwise you get an if-then-else ladder.
-0xe1a

On Sun, Aug 29, 2010 at 9:52 AM, Josh Suereth <joshua.suereth@gmail.com> wrote:
import annotation.switch

object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
}

import WeekDay._

class Test {
  def couldThisBeOptimised(x : WeekDay) = x match {
    case Mon => "Case of the Mondays"
    case Tue => "Ruby Tuesdays?"
    case Fri => "Thank God!"
    case _ => "Not an interesting day"
  }
}

Just for fun, I tried to see if I could force this by hand:
object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
  val Mon_ID = Mon.id;
  val Tue_ID = Tue.id;
  val Wed_ID = Wed.id;
  val Thu_ID = Thu.id;
  val Fri_ID = Fri.id;
  val Sat_ID = Sat.id;
  val Sun_ID = Sun.id;
}
import WeekDay._
scala> def notOptimisedEnum(x : WeekDay) = (x.id : @switch) match {
     |     case Mon_ID => "Case of the Mondays"
     |     case Tue_ID => "Ruby Tuesdays?"
     |     case Fri_ID => "Thank God!"
     |     case _ => "Not an interesting day"
     |   }
<console>:13: error: could not emit switch for @switch annotated match
       def notOptimisedEnum(x : WeekDay) = (x.id : @switch) match {

So, my question is:  How relevant is emitting a tableswitch bytecode when pattern matching an Enumeration?   This seems like a chalk against Scala enumerations (and for encoding enumerations inside Java).   However, I haven't ever had a tight loop where I had to rely on the tableswitch bytecode for performance before, so I was wondering what everyone else thought here.






--
« Je déteste la montagne, ça cache le paysage »
Alphonse Allais
Joshua.Suereth
Joined: 2008-09-02,
User offline. Last seen 32 weeks 6 days ago.
Re: {mailcleaner} Re: Can I get an optimisation?
True, but the order is known at compile time.  If you can verify that the Enumeration class is closed, the compiler would know in what order IDs are created and hence you could perform the optimisation.   Yes, this is more of a hack.

Also, upon reflection, I don't think anyone but my hardcore C coworkers would care about this table switch.  If Java enumerations don't support it, then we're probably ok in Scala.

On Mon, Aug 30, 2010 at 5:30 AM, iulian dragos <iulian.dragos@epfl.ch> wrote:
Unfortunately, this is impossible. A tableswitch requires that the alternatives are statically known, as int values. The weekday object is generating ids at runtime, so the method bytecode would need to be generated reflectively, probably ending up much slower than a bunch of ifs.
For instance, this works:
  final val ONE = 1  final val TWO = 2   final val THREE = 3
  def testOpt2(x: Int) = (x: @switch) match {     case ONE => "a"    case TWO => "b"     case _ => "c"  }
iulian

On Sun, Aug 29, 2010 at 7:16 PM, Josh Suereth <joshua.suereth@gmail.com> wrote:
Good to know.  It also makes sense.   I was running through an algorithm to determine if you could optimise the enumeration.   They all rely on the premise that the code with the pattern match would get recompiled after the enumeration changes.  As I've worked in too many projects, I know there will be the case where this doesn't happen and subtle bugs would be introduced.    However, you could potentially make the optimisation available as a -Y option, and emit warnings if the enumeration + switch are in separate compilation units.

In any case, I was just curious if anyone had thought about this, or if it was even useful enough to pay attention to it.

On Sun, Aug 29, 2010 at 1:11 PM, Alex Cruise <alex@cluonflux.com> wrote:
javac only emits a switch opcode when the switch statement is in the same compilation unit (i.e. file) as the enum is declared.  Otherwise you get an if-then-else ladder.
-0xe1a

On Sun, Aug 29, 2010 at 9:52 AM, Josh Suereth <joshua.suereth@gmail.com> wrote:
import annotation.switch

object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
}

import WeekDay._

class Test {
  def couldThisBeOptimised(x : WeekDay) = x match {
    case Mon => "Case of the Mondays"
    case Tue => "Ruby Tuesdays?"
    case Fri => "Thank God!"
    case _ => "Not an interesting day"
  }
}

Just for fun, I tried to see if I could force this by hand:
object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
  val Mon_ID = Mon.id;
  val Tue_ID = Tue.id;
  val Wed_ID = Wed.id;
  val Thu_ID = Thu.id;
  val Fri_ID = Fri.id;
  val Sat_ID = Sat.id;
  val Sun_ID = Sun.id;
}
import WeekDay._
scala> def notOptimisedEnum(x : WeekDay) = (x.id : @switch) match {
     |     case Mon_ID => "Case of the Mondays"
     |     case Tue_ID => "Ruby Tuesdays?"
     |     case Fri_ID => "Thank God!"
     |     case _ => "Not an interesting day"
     |   }
<console>:13: error: could not emit switch for @switch annotated match
       def notOptimisedEnum(x : WeekDay) = (x.id : @switch) match {

So, my question is:  How relevant is emitting a tableswitch bytecode when pattern matching an Enumeration?   This seems like a chalk against Scala enumerations (and for encoding enumerations inside Java).   However, I haven't ever had a tight loop where I had to rely on the tableswitch bytecode for performance before, so I was wondering what everyone else thought here.






--
« Je déteste la montagne, ça cache le paysage »
Alphonse Allais

Michael Bayne
Joined: 2010-08-31,
User offline. Last seen 42 years 45 weeks ago.
Re: {mailcleaner} Re: Can I get an optimisation?

On Mon, Aug 30, 2010 at 4:05 AM, Josh Suereth wrote:
> Also, upon reflection, I don't think anyone but my hardcore C coworkers
> would care about this table switch.  If Java enumerations don't support it,
> then we're probably ok in Scala.

OpenJDK javac compiles enum switches to tableswitch, c.f.:

8: invokevirtual #4; //Method Test$Foo.ordinal:()I
11: iaload
12: tableswitch{ //1 to 3
1: 40;
2: 51;
3: 62;
default: 70 }

And it relies on internal compiler hackery to determine the static
value of the enum ordinals.

Iulian Dragos 2
Joined: 2009-02-10,
User offline. Last seen 42 years 45 weeks ago.
Re: {mailcleaner} Re: Can I get an optimisation?


On Mon, Aug 30, 2010 at 1:05 PM, Josh Suereth <joshua.suereth@gmail.com> wrote:
True, but the order is known at compile time.  If you can verify that the Enumeration class is closed, the compiler would know in what order IDs are created and hence you could perform the optimisation.   Yes, this is more of a hack.

It means the compiler has to know about the implementation of Value, so then Enumeration becomes a language feature, instead of a library class. I'm not sure it's worth it.
iulian 

Also, upon reflection, I don't think anyone but my hardcore C coworkers would care about this table switch.  If Java enumerations don't support it, then we're probably ok in Scala.

On Mon, Aug 30, 2010 at 5:30 AM, iulian dragos <iulian.dragos@epfl.ch> wrote:
Unfortunately, this is impossible. A tableswitch requires that the alternatives are statically known, as int values. The weekday object is generating ids at runtime, so the method bytecode would need to be generated reflectively, probably ending up much slower than a bunch of ifs.
For instance, this works:
  final val ONE = 1  final val TWO = 2   final val THREE = 3
  def testOpt2(x: Int) = (x: @switch) match {     case ONE => "a"    case TWO => "b"     case _ => "c"  }
iulian

On Sun, Aug 29, 2010 at 7:16 PM, Josh Suereth <joshua.suereth@gmail.com> wrote:
Good to know.  It also makes sense.   I was running through an algorithm to determine if you could optimise the enumeration.   They all rely on the premise that the code with the pattern match would get recompiled after the enumeration changes.  As I've worked in too many projects, I know there will be the case where this doesn't happen and subtle bugs would be introduced.    However, you could potentially make the optimisation available as a -Y option, and emit warnings if the enumeration + switch are in separate compilation units.

In any case, I was just curious if anyone had thought about this, or if it was even useful enough to pay attention to it.

On Sun, Aug 29, 2010 at 1:11 PM, Alex Cruise <alex@cluonflux.com> wrote:
javac only emits a switch opcode when the switch statement is in the same compilation unit (i.e. file) as the enum is declared.  Otherwise you get an if-then-else ladder.
-0xe1a

On Sun, Aug 29, 2010 at 9:52 AM, Josh Suereth <joshua.suereth@gmail.com> wrote:
import annotation.switch

object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
}

import WeekDay._

class Test {
  def couldThisBeOptimised(x : WeekDay) = x match {
    case Mon => "Case of the Mondays"
    case Tue => "Ruby Tuesdays?"
    case Fri => "Thank God!"
    case _ => "Not an interesting day"
  }
}

Just for fun, I tried to see if I could force this by hand:
object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
  val Mon_ID = Mon.id;
  val Tue_ID = Tue.id;
  val Wed_ID = Wed.id;
  val Thu_ID = Thu.id;
  val Fri_ID = Fri.id;
  val Sat_ID = Sat.id;
  val Sun_ID = Sun.id;
}
import WeekDay._
scala> def notOptimisedEnum(x : WeekDay) = (x.id : @switch) match {
     |     case Mon_ID => "Case of the Mondays"
     |     case Tue_ID => "Ruby Tuesdays?"
     |     case Fri_ID => "Thank God!"
     |     case _ => "Not an interesting day"
     |   }
<console>:13: error: could not emit switch for @switch annotated match
       def notOptimisedEnum(x : WeekDay) = (x.id : @switch) match {

So, my question is:  How relevant is emitting a tableswitch bytecode when pattern matching an Enumeration?   This seems like a chalk against Scala enumerations (and for encoding enumerations inside Java).   However, I haven't ever had a tight loop where I had to rely on the tableswitch bytecode for performance before, so I was wondering what everyone else thought here.






--
« Je déteste la montagne, ça cache le paysage »
Alphonse Allais




--
« Je déteste la montagne, ça cache le paysage »
Alphonse Allais

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland