-
Notifications
You must be signed in to change notification settings - Fork 9
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
721 Trace flush bug fixes #722
Conversation
Codecov Report
@@ Coverage Diff @@
## develop #722 +/- ##
===========================================
- Coverage 79.17% 79.17% -0.01%
===========================================
Files 333 333
Lines 10162 10164 +2
===========================================
+ Hits 8046 8047 +1
- Misses 2116 2117 +1
|
@@ -219,7 +219,7 @@ struct Trace { | |||
vt_gzFile* file, NodeType const node, double const start | |||
); | |||
|
|||
void writeTracesFile(int flush); | |||
void writeTracesFile(int flush, bool is_incremental_flush); |
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.
is_incremental
sufficient intent.
src/vt/trace/trace.cc
Outdated
|
||
if (is_incremental_flush) { | ||
vt::trace::TraceScopedEvent scope(flush_event); | ||
outputTraces( |
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.
Duplicate feels odd. Maybe always have an event? (incremental or full).
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 agree the duplicate feels odd. However, I can't have an event when doing the final (non-incremental) flush because it will add an event after the trace gets finalized.
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.
Can a TraceScopedEvent be a 'no-op'? Might not have that support.
vt::trace::TraceScopedEvent scope(is_incremental_flush ? flush_event_ : no_op_event_);
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.
No, that is isn't supported. I could add that support
@@ -755,13 +759,6 @@ TraceEventIDType Trace::logEvent(LogType&& log) { | |||
TraceEventIDType event = log.event; | |||
traces_.push(std::move(log)); | |||
|
|||
// If auto-flush, can flush immediately. |
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.
Implies tracing only flushed in during phase shift.
Seems fine, but this might be the last usage of vt_trace_flush_size other than as a flag detached from meaning.
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.
As far as trace flushing, perhaps on BeginIdle might be a good location to always flush every trace that is present. If that was a reasonable place, it might be possible to eliminate the flush_size setting entirely, eg.
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.
Unfortunately, BeginIdle is not a good location for flushing. For flushing to not impact performance, it must be synchronized across nodes. A short idle period will not cover the latency/bandwidth to disk.
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 another note, I was thinking it could spread cost and possibly be more efficient overall of writing the traces directly to a byte-buffer (snprintf, eg) and then in the flush simply sending the prewritten buffers to gzip.
- CPU time of printf is spread to trace sites; could explore alternative formatters (many options: https://stackoverflow.com/a/50260393/2864740) as such separate from zlibs formatting support. That said, not sure if the printf-family can be beat for simple non-formatted integers writing to some hunk of chars..
- No need to keep around traces_ structure (would keep around around a deque of char[1MB] or whatever instead)
- No need to copy the trace log events into said structure either.
- Implicitly forms 'slab' allocations, with re-usable pool
- Allows 'flush by size', if such was a request. (However, if flushing is only and always+completely done during the LB then this does not apply.)
- Flush sites effectively limited to writing stream to gzip+IO (which has the cost of zipping, without the cost of formatting).
Cons:
- Time of format may be more than time-to-queue, fsvo.
- Write to buffer, write buffer to stream
- Lose semantic of traces-to-write
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.
https://www.boost.org/doc/libs/1_52_0/libs/spirit/doc/html/spirit/karma/performance_measurements/numeric_performance/int_performance.html -- very slight lead in some cases? :D (Actually, that compares itoa, not even printf.. and the numbers are older.)
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 an idea. Let's add an opt-in flag for flush at idle. I don't think in general we can tolerate that many writes to disk that often in performance-critical settings.
@@ -653,8 +657,8 @@ void Trace::setTraceEnabledCurrentPhase(PhaseType cur_phase) { | |||
|
|||
// Go ahead and perform a trace flush when tracing is disabled (and was |
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.
Not in this change, but I still feel something is off with the enable/disable transition above. At the very least the "..we are disabling traces.." is a misleading statement when tracing is disabled -> enabled.
I was thinking about the problem and I think it might be good to, when tracing is disabled, still allow end processing events. Then the open events are not unwound and is guaranteed free from corruption.
Here is a case where stack imbalance might be able to occur:
event = theTrace()->beginProcessing(..);
setTraceEnabledCurrentPhase(); // manipulates stack here
theTrace->endProcessing(event); // no matching event to close = assert failure
The standard enable/disable are broken for the same manner.
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.
bool isTraceEnabled(eventType)
-> EndProcessing/EndIdle are always allowed if tracing is enabled via node/configuration. Other event types are also subject to the dynamic settings.
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 sort of understand your point, but not completely. There isn't a bug because in the disable -> enable transition the event
returned from beginProcessing
is essentially nil. In the enable -> disable transition, Trace::setTraceEnabledCurrentPhase
will actually forcibly unwind the stack and close all events at that point before it's disabled.
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.
Scenario:
- Given tracing is enabled.
- A begin processing event is written, and the processing tag returned. This is done at the start of a nested scheduler loop in Tracing bug: begin/end idle events mixed with begin/end processing #703, and from some other message processing locations.
- Somewhere after this call and before the paired end processing call, possibly on a nested stack frame, tracing is disabled (via normal disable, or via phase) when the previous processing event has not been end'ed by the taker of the tag.
- The code unwinds the open event stack.
- Later one the stack unwinds and the code that called begin processing calls end processing with the tag it acquired - except this tag is no longer valid.
So if there is ever a way that this could could run as part of a nested scheduler, or as some handler either now (or in the future) added begin end processing tags, surrounding the operation, then kapow.
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.
As far as the comment:
if (trace_enabled_cur_phase_ != ret) {
if (tracingWasEnabled) { // enable -> disabled
// Close and pop everything, we are disabling traces at this point
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.
Ah, I get the problem now. This is a definitely a real problem interacting with #703
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 would check interactions with #703 which may inadvertently affect the open event unwinding. (I plan to do so later.)
Even when unwinding, I would ensure to only do so for the enabled -> disabled case (even if the stack is presumed to be empty going in the other direction) for clarity.
I can update #703 to ensure that close processing/idle events are allowed (trace statically enabled, dynamically disabled), which would remove the extra stack unwinding entirely with the very minor caveat that an open event, if any, wouldn't actually be written to the trace until the subsequent flush.
So will you address this in #703? Should I merge this? |
@lifflander Changes are on #703 to beta.6 PR now. I need to git (get?!) those changes back on another branch to merge down.. haven't tried with the phase enable/disable, but the test scenario with broadcasts + barriers + random trace starts+stops appears successful. |
d01ab3c
to
e62faeb
Compare
0e6794f
to
c31959d
Compare
Rebased onto current origin/develop and force pushed. Slight method reorderings. |
@pnstickne This is ready to go once it is rebased? |
76318a8
to
c31959d
Compare
c31959d
to
17826cb
Compare
Fixes #721