-
-
Notifications
You must be signed in to change notification settings - Fork 243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Asynchronous Stack Traces for Task #1267
Conversation
import java.util.Optional; | ||
|
||
/** | ||
* All Credits to https://github.com/typelevel/cats-effect and https://github.com/RaasAhsan |
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.
I have just added this comment to all files that I copy-pasted with minimal changes
I'm not sure how should I give credits properly (and in a legal way) - I'm more than happy to follow any suggestions @RaasAhsan , @djspiewak
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.
IMO this is pretty much all that is really needed. From an etiquette standpoint, this seems ample. From a legal standpoint, both Monix and CE are under ASLv2, so derivative works like this are entirely expected and normal.
/** | ||
* All Credits to https://github.com/typelevel/cats-effect and https://github.com/RaasAhsan | ||
*/ | ||
final case class TaskTrace(events: List[TaskEvent], captured: Int, omitted: Int) { |
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.
I'm wondering whether classes like that should be reused with Cats-Effect, or not.
I suppose it's safer to have it separate and create a type class if there are any libraries that operate on it.
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.
Another idea would be to slurp this out into a common library which both can share. You would probably also be interested in the ConcurrentHashMap
replacement that we're working on for 2.2.1, which should shrink the performance hit pretty dramatically.
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.
@djspiewak that looks interesting, where can I learn more about what replacement you're preparing for ConcurrentHashMap
?
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.
@jvican typelevel/cats-effect#1101
It's not a general replacement. CHM is actually insanely good at what it does. But tracing is a rather weird case. The cache converges to a relatively small size (strictly bounded by the number of classes) and then usually never changes again. Cache misses aren't fatal, they're just poorly optimized, and writes are not mandatory (follows from the miss bit). But within the context of all of that, we want reads to be blisteringly fast once fully converged.
In our synthetic benchmarks, tracing imposes a roughly 16% performance penalty on programs' straight-line performance (i.e. long chains of flatMap
s). From what we can tell, nearly all of that is tied up in just reading from ConcurrentHashMap
, due to the memory barriers which are necessary to ensure proper consistency, and secondarily due to the fact that the table doesn't aggressively optimize for a small and convergent set of keys. We can relax both of those constraints with a custom implementation and theoretically shave quite a bit off of that performance penalty.
Still a work in progress. :-)
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.
Another idea would be to slurp this out into a common library which both can share.
That would be nice. Most of the code seems to be nicely separated and quite generic
Currently, I'm fine with copy-pasting and keeping an eye on updates but I will probably get tired of it pretty quickly, considering I plan to do the same for Coeval
and monix-bio
in the future
You would probably also be interested in the ConcurrentHashMap replacement that we're working on for 2.2.1, which should shrink the performance hit pretty dramatically.
Sounds awesome!
Could you use any help?
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.
That would be nice. Most of the code seems to be nicely separated and quite generic
Currently, I'm fine with copy-pasting and keeping an eye on updates but I will probably get tired of it pretty quickly, considering I plan to do the same for Coeval and monix-bio in the future
We should definitely pull it upstream into a new lib then. This is also relevant for CE3, where we want to reimplement tracing, but it would be nice to not have to duplicate things. Ideas on a name? I rather like Sacagawea (tracking, tracing, etc), partially because Native American names and words are sorely underrepresented in the software space, and partially because she's cool and it seems like a distinctive name.
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.
👍 on factoring out code for reusability. I would start with something like the UnsafeConvergentCache
because it's actually very general-purpose and initialization-safe, thread-unsafe data structures may have applications outside tracing. Pulling out tracing-specific code like IOTrace
/TaskTrace
is also an awesome idea, but my only caution is that functionality will most certainly evolve in the CE2/CE3/Monix world (e.g. thread tracking will be introduced to CE2 soon), and saying that they won't diverge is probably short-sighted. It would be unfortunate to end up in a situation where the library prescribes too much on implementations or implementations are restricted by the library, but I think we can definitely find a middle ground. Ultimately if things don't work out, we should be able to sever the dependency easily (keeping use of that library internal is probably a reasonable precaution).
Currently, I'm fine with copy-pasting and keeping an eye on updates but I will probably get tired of it pretty quickly, considering I plan to do the same for Coeval and monix-bio in the future
If there are any improvements, it would be awesome to see those back in CE as well! :D But that's a really good reason to share all this code.
I rather like Sacagawea (tracking, tracing, etc), partially because Native American names and words are sorely underrepresented in the software space, and partially because she's cool and it seems like a distinctive name.
Sacagawea is an awesome name :)
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.
Sacagawea is an awesome name :)
I can create a repo and set up some infra for it a little later this morning and you guys can shovel things in there as you see fit. :-) If it turns out to not be a good idea, it's always easy to un-shovel.
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.
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.
Okay, I think I'll try to settle this PR as is, and then we could move towards keeping internals in sacagawea
. Hopefully, I can find some improvements to pay you back a little. :)
I've counted only three public pieces (apart from configuration):
final case class IOTrace(events: List[IOEvent], captured: Int, omitted: Int)
IOEvent
PrintingOptions
And it should be perfectly fine to keep it per library, mostly cosmetic stuff apart from IOTrace
.
In case of IOTrace
, we could just use a type class in any future libraries.
Pulling out tracing-specific code like IOTrace/TaskTrace is also an awesome idea, but my only caution is that functionality will most certainly evolve in the CE2/CE3/Monix world (e.g. thread tracking will be introduced to CE2 soon)
Could you elaborate on this feature?
I'm wondering about IOTrace#showFiberTrace
for other types of events.
Would it add extra lines about the current Thread
?
* Global cache for trace frames. Keys are references to lambda classes. | ||
* Should converge to the working set of traces very quickly for hot code paths. | ||
*/ | ||
private[this] val frameCache: ConcurrentHashMap[Class[_], TaskEvent] = new ConcurrentHashMap() |
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.
Echoing my comment from typelevel/cats-effect#1101 (comment)
Storing strong references to the lambda classes as the key of the frame cache smells like a potential classloader leak when the lambda class is loaded from a classloader with a shorter lifecycle than cats-eval's classloader.
java.lang.ClassValue
is designed to avoid such leaks. It's also designed to be extremely fast for lookups.
BTW @jvican - do you have any performance tests in bloop? In microbenchmarks, I experience 10-30% slow-down for cached tracing |
Hey @Avasil, I have performance tests in bloop but bloop hasn't yet migrated to 3.x, it's something I'm planning to get around to soon, so unfortunately we won't be able to use our performance checks for a real-world performance evaluation.
What do you mean by cached tracing? Will this be the baseline when tracing is enabled by default? |
There are multiple configurations of tracing: https://typelevel.org/cats-effect/tracing/#configuration It is going to be default but it can be disabled if someone notices any performance degradation |
This would be a very helpful feature. If a small release can be done that includes this feature, that would be great |
@9rb I plan to finish this PR and do an official release within two weeks but there is a snapshot that you could try: |
|
Fixes #1015
Latest snapshot version:
3.2.2+55-9adf112c-SNAPSHOT
This is a direct port of
cats.effect.IO
solution, released in 2.2.0.Tracing docs
See the following PR's for more context:
So pretty much all credit goes to @RaasAhsan and @djspiewak 👏
TODO:
The feature works exactly the same as in Cats-Effect and is enabled by default.
It can be configured the same way as Cats version, which is documented here
The prefix is
monix.eval
instead ofcats.effect
e.g.:-Dmonix.eval.stackTracingMode=full -Dmonix.eval.traceBufferLogSize=5
Example of the current state:
Old stack trace:
Cached Mode:
Full Tracing Mode: