Skip to content

Conversation

@johnynek
Copy link
Collaborator

This can avoid some cases of double boxing. When we use for instance, Semigroup[T] and T happens to be Long, then we can still box despite the specialized call because T was generic where the Semigroup was used (I believe that is true).

Doing sum with plus means, unboxing the accumulator and the next item, adding them, boxing the result and starting again. This gives about N boxing operations and 2N unboxing operations for N items to sum. If we do sum internally, we know the type, so we only have to unbox from the TraverableOnce, which gives N unboxing operations.

@johnynek
Copy link
Collaborator Author

mima crashed on this. Trying to bump to the latest and see if that helps.

@ianoc
Copy link
Collaborator

ianoc commented Jun 27, 2016

LGTM -- did you manage to get any benchmark/profile to illustrate?

}
override def sum(t: TraversableOnce[Float]): Float = {
var sum = 0.0f
t.foreach(sum += _)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did we find out in the CMS PR that foreach doesn't compile down to a while?
should this be a while loop? I could imagine dynamic dispatch on a closure costingmore than boxing, but who knows

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Closure usage is far far cheaper than boxing. I guess its to do with inlining or new gen allocations. But boxing will show up orders of magnitude higher than it. But seems reasonable to eliminate it here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK thanks, didn't really have an intuition for what the cost of method dispatch vs boxing (object allocation?) is. But yeah, seems like here we might as well use a while anyway.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only catch is TraversableOnce has no way to use while without toIterator. In that case, building an iterator can be more expensive that foreach. Consider an array. If you need to write foreach for an array, you can do:

def foreach(f: T => Unit): Unit = {
  var idx = 0
  while(idx < arr.length) {
   f(arr(idx))
    idx += 1
  }
}

Which can be cheaper than wrapping with an Iterator.

I think we should assume foreach is fine until we really want to geek out on different data structure testing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's a good point, didn't realize that TraversableOnce only has a conversion to Iterator.

@isnotinvain
Copy link
Contributor

+1, 2 minor comments if you think they are worth addressing (but without benchmarks, not really worth too much thought probably)

@isnotinvain
Copy link
Contributor

+1

@johnynek johnynek merged commit 232dac3 into develop Jun 27, 2016
@johnynek johnynek deleted the oscar/sumOptionNumerics branch June 27, 2016 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants