-
Notifications
You must be signed in to change notification settings - Fork 265
Track state in summingbird-online as an Iterator rather than a Seq. #703
Conversation
…his should avoid n^2 compute comlexity when summing single element lists of Storm tuples.
could we use |
Good idea. Changed to use stream instead of iterator. |
tbh Iterator is 4x faster than stream in this microbenchmark but both are way faster than List, so stream seems fine: @benchmark @benchmark @benchmark Results: |
I would bet Batched will be as fast or faster than Iterator.
…On Sat, Dec 24, 2016 at 18:15 Pankaj Gupta ***@***.***> wrote:
tbh Iterator is 4x faster than stream in this microbenchmark but both are
way faster than List, so stream seems fine:
val s = (0 to 10000).toList
@benchmark <https://github.com/Benchmark>
def listConcat(): List[Int] = {
s ++ List(0)
}
@benchmark <https://github.com/Benchmark>
def streamConcat(): Stream[Int] = {
s.toStream ++ Stream(0)
}
@benchmark <https://github.com/Benchmark>
def iterConcat(): Iterator[Int] = {
s.toIterator ++ Iterator.single(0)
}
Results:
[info] ToBenchmark.iterConcat thrpt 4 85182247.256 ± 5840222.962 ops/s
[info] ToBenchmark.listConcat thrpt 4 9937.918 ± 26498.037 ops/s
[info] ToBenchmark.streamConcat thrpt 4 22019587.193 ± 7199199.008 ops/s
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#703 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAEJdpCK_zBnqzN-dyCdF8YtGW_3fhfxks5rLe3YgaJpZM4LVMH_>
.
|
I tried Batched but the code started getting complicated because of https://github.com/twitter/summingbird/blob/develop/summingbird-online/src/main/scala/com/twitter/summingbird/online/executor/AsyncBase.scala#L46 We need to be able to pass an empty Batched here. Batched itself doesn't have a zero value it relies on the contained type. So we either have to use Option[Batched] which wouldn't be good for performance, always having to wrap/unwrap. Or we have to have the monoid of S available in this abstract class, which would require further code changes. |
Just for comparison iterator and Batched are indeed comparable in perf. I'd really like to use Batched if we could find a simple way or iterator otherwise. Combining input state is in the hot path.: @benchmark @benchmark @benchmark @benchmark [info] ToBenchmark.batchedConcat thrpt 4 126300963.122 ± 46804561.489 ops/s |
Any suggestions on the next steps here. I'm ok with Stream, it's still much better than List in this case. |
I have not investigated why the tests are red. If we can make them green with something faster. I'd be happy to do that. I don't think using Batched would be too much work. Or we could copy this code or add this dependency: https://github.com/non/chain/blob/master/src/main/scala/chain/Chain.scala It is a single file library that is the more general version of Batched (it has empty), it was written by @non who also wrote Batched. Do we really need an empty Batched? I would imagine that a It is up to you. I think killing the O(N^2) is most important. Losing a constant factor of 4 is probably not a huge deal if you don't want to work on this other stuff. Not using a mutable data structure is pretty important to me since this code has been worked on by many people now, and it is much easier to make a mistake with mutable APIs. |
Thanks let me try chained. I agree, constant factor of 4 is insignificant
compared to n^2. Tests are failing the Mima check.
…On Mon, Jan 2, 2017 at 10:04 AM P. Oscar Boykin ***@***.***> wrote:
I have not investigated why the tests are red.
If we can make them green with something faster. I'd be happy to do that.
I don't think using Batched would be too much work. Or we could copy this
code or add this dependency:
https://github.com/non/chain/blob/master/src/main/scala/chain/Chain.scala
It is a single file library that is the more general version of Batched
(it has empty), it was written by @non <https://github.com/non> who also
wrote Batched.
Do we really need an empty Batched? I would imagine that a
Monoid[Option[Batched[T]]] would be almost as fast (still faster than
Stream).
It is up to you. I think killing the O(N^2) is most important. Losing a
constant factor of 4 is probably not a huge deal if you don't want to work
on this other stuff.
Not using a mutable data structure is pretty important to me since this
code has been worked on by many people now, and it is much easier to make a
mistake with mutable APIs.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#703 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAojhv2OALNrtkVtF2XM1awk5KsqCOuAks5rOTwWgaJpZM4LVMH_>
.
|
Can you add the exclusions to so we can keep the tests green? It prints
what you need to add to the build to exclude those methods from erroring.
On Mon, Jan 2, 2017 at 9:09 AM Pankaj Gupta <[email protected]>
wrote:
… Thanks let me try chained. I agree, constant factor of 4 is insignificant
compared to n^2. Tests are failing the Mima check.
On Mon, Jan 2, 2017 at 10:04 AM P. Oscar Boykin ***@***.***>
wrote:
> I have not investigated why the tests are red.
>
> If we can make them green with something faster. I'd be happy to do that.
>
> I don't think using Batched would be too much work. Or we could copy this
> code or add this dependency:
>
>
https://github.com/non/chain/blob/master/src/main/scala/chain/Chain.scala
>
> It is a single file library that is the more general version of Batched
> (it has empty), it was written by @non <https://github.com/non> who also
> wrote Batched.
>
> Do we really need an empty Batched? I would imagine that a
> Monoid[Option[Batched[T]]] would be almost as fast (still faster than
> Stream).
>
> It is up to you. I think killing the O(N^2) is most important. Losing a
> constant factor of 4 is probably not a huge deal if you don't want to
work
> on this other stuff.
>
> Not using a mutable data structure is pretty important to me since this
> code has been worked on by many people now, and it is much easier to
make a
> mistake with mutable APIs.
>
> —
> You are receiving this because you authored the thread.
>
>
> Reply to this email directly, view it on GitHub
> <#703 (comment)
>,
> or mute the thread
> <
https://github.com/notifications/unsubscribe-auth/AAojhv2OALNrtkVtF2XM1awk5KsqCOuAks5rOTwWgaJpZM4LVMH_
>
> .
>
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#703 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAEJdsU6cNEO-Wai0iYGYHNXOgmudGDDks5rOUuEgaJpZM4LVMH_>
.
|
Sure I'll take a look later today.
On Mon, Jan 2, 2017 at 11:37 AM P. Oscar Boykin <[email protected]>
wrote:
… Can you add the exclusions to so we can keep the tests green? It prints
what you need to add to the build to exclude those methods from erroring.
On Mon, Jan 2, 2017 at 9:09 AM Pankaj Gupta ***@***.***>
wrote:
> Thanks let me try chained. I agree, constant factor of 4 is insignificant
> compared to n^2. Tests are failing the Mima check.
>
> On Mon, Jan 2, 2017 at 10:04 AM P. Oscar Boykin <
***@***.***>
> wrote:
>
> > I have not investigated why the tests are red.
> >
> > If we can make them green with something faster. I'd be happy to do
that.
> >
> > I don't think using Batched would be too much work. Or we could copy
this
> > code or add this dependency:
> >
> >
>
https://github.com/non/chain/blob/master/src/main/scala/chain/Chain.scala
> >
> > It is a single file library that is the more general version of Batched
> > (it has empty), it was written by @non <https://github.com/non> who
also
> > wrote Batched.
> >
> > Do we really need an empty Batched? I would imagine that a
> > Monoid[Option[Batched[T]]] would be almost as fast (still faster than
> > Stream).
> >
> > It is up to you. I think killing the O(N^2) is most important. Losing a
> > constant factor of 4 is probably not a huge deal if you don't want to
> work
> > on this other stuff.
> >
> > Not using a mutable data structure is pretty important to me since this
> > code has been worked on by many people now, and it is much easier to
> make a
> > mistake with mutable APIs.
> >
> > —
> > You are receiving this because you authored the thread.
> >
> >
> > Reply to this email directly, view it on GitHub
> > <
#703 (comment)
> >,
> > or mute the thread
> > <
>
https://github.com/notifications/unsubscribe-auth/AAojhv2OALNrtkVtF2XM1awk5KsqCOuAks5rOTwWgaJpZM4LVMH_
> >
> > .
> >
>
> —
> You are receiving this because you commented.
>
>
> Reply to this email directly, view it on GitHub
> <#703 (comment)
>,
> or mute the thread
> <
https://github.com/notifications/unsubscribe-auth/AAEJdsU6cNEO-Wai0iYGYHNXOgmudGDDks5rOUuEgaJpZM4LVMH_
>
> .
>
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#703 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAojht74AChMPen2r3kCCNADToPp9s9Sks5rOVHggaJpZM4LVMH_>
.
|
Chain seems good: I've updated the review with now using chain. |
Tests pass now, just waiting for shipit to merge. |
@@ -149,12 +150,13 @@ case class BaseBolt[I, O](jobID: JobId, | |||
} | |||
} | |||
|
|||
private def finish(inputs: Stream[InputState[Tuple]], results: TraversableOnce[O]) { | |||
private def finish(inputs: Chain[InputState[Tuple]], results: TraversableOnce[O]) { | |||
val tuples = inputs.iterator.map(_.state).toList |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't we move this line to 158 (only materialize the List
if we have dependants and we anchor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My reasoning was that we need to iterate through the chain anyway to get the size for the log statement at the end of function but I agree, materialization of list should be avoided as well in those cases. Proposed a fix.
var emitCount = 0 | ||
if (hasDependants) { | ||
if (anchorTuples.anchor) { | ||
results.foreach { result => | ||
val tuples = inputs.iterator.map(_.state).toList | ||
numTuples = Some(tuples.size) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
list .size
is O(N)
not O(1)
. So if we are going to do this, why use the var and not just use use inputs.iterator.size
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. We should be able to calculate the size and list in one pass though. Let me try.
var emitCount = 0 | ||
if (hasDependants) { | ||
if (anchorTuples.anchor) { | ||
results.foreach { result => | ||
val tuples = inputs.iterator.map(_.state).toList |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't we want this above the foreach? We don't want to recompute tuples
for each result. We just want it once and then reuse for all results, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, good idea. I believe this was how it was in original code too so I didn't notice. Let me try to fix this.
Current coverage is 70.96% (diff: 80.95%)
|
👍 |
What is a reason to expose To be more precise - |
I think making a follow up PR that minimized the scope of visibility of Chain (maybe even walking back some of the mima exclusions) would be fine. But if we have to copy to do it, I would not. For instance, you can go: So, maybe we could use That said, these are fairly "private" classes in that 99% of summingbird users would never use them. In fact, likely only storm/heron platform would use them. |
I agree. Regarding to copying - we don't need |
I agree exposing chain at OperationContainer is not ideal and also that OperationContainer is used only in storm/heron platform right now, so I feel it's better to keep it simple, as is, for now. Let me create an issue to capture this though. |
Fix for #689 . This should avoid n^2 compute complexity when summing single element lists of Storm tuples.