This is an archive of the discontinued LLVM Phabricator instance.

[trace][intel pt] Handle better tsc in the decoder
ClosedPublic

Authored by wallace on Mar 31 2022, 10:42 PM.

Details

Summary

A problem that I introduced in the decoder is that I was considering TSC decoding
errors as actual instruction errors, which mean that the trace has a gap. This is
wrong because a TSC decoding error doesn't mean that there's a gap in the trace.
Instead, now I'm just counting how many of these errors happened and I'm using
the dump info command to check for this number.

Besides that, I refactored the decoder a little bit to make it simpler, more
readable, and to handle TSCs in a cleaner way.

Diff Detail

Event Timeline

wallace created this revision.Mar 31 2022, 10:42 PM
Herald added a project: Restricted Project. · View Herald TranscriptMar 31 2022, 10:42 PM
wallace requested review of this revision.Mar 31 2022, 10:42 PM
Herald added a project: Restricted Project. · View Herald TranscriptMar 31 2022, 10:42 PM
zrthxn accepted this revision.Apr 1 2022, 1:04 AM
This revision is now accepted and ready to land.Apr 1 2022, 1:04 AM

The changes to the decoder look sound, just left two questions related to it and a couple other nits.

lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
120

The parameter is unused, is there a reason to keep this or should it be removed since the method is simply incrementing the tsc error count?

lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
230
lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
106

see comment on DecodeInstructions

130

see comment on DecodeInstructions

138

see comment on DecodeInstructions

159

This function isn't taking ownership/storing this SP so consider just passing a reference here and in the AppendError, AppendInstruction and RefreshTsc funcs

192

This makes sense to not include the errors if you are at the end of the stream, I have two questions related to this:

  1. Prior to this change, was there always at least one error in the instructions from the eos that occurs when tracing? My understanding is that eos as a result of pt_insn_next is an indication that you are at the end of the buffer and thus the decoding is done, is that correct?
  2. When a pt_insn_next call returns pte_eos, does that gurantee that the next call to FindNextSynchronizationPoint will return pte_eos as well? If so, could this code be changed to immediately return if pte_eos is returned here since currently it will break from the inner loop, go back to the top of the outer loop, call FindNextSynchronizationPoint which will ultimately return pte_eos which causes a break from the outer loop and finally the implicit return from the function? Seems like we could fail fast by immediately returning from the function here if pt_insn_next returns pte_eos.
jj10306 added inline comments.Apr 1 2022, 9:48 AM
lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
245–247

nit: When I initially read "Report" it made me think that the last TSC was being logged or reported to something else. Since all this method does is record the tsc of the last instruction, potentially "Record" is a better name. This is purely my opinion so feel free to keep it as is or change it (:

wallace added inline comments.Apr 1 2022, 10:36 AM
lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
120

good catch. I initially wanted to show the list of actual errors happening. I'll do that now

lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
245–247

good idea

lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
159

good idea :)

192

Prior to this change, was there always at least one error in the instructions from the eos that occurs when tracing?

Not really. In line 128 of the original code we had:

if (errcode == -pte_eos)
      break;

which broke the instruction decoding flow as soon as an eos is seen.

My understanding is that eos as a result of pt_insn_next is an indication that you are at the end of the buffer and thus the decoding is done, is that correct?

yes, that is true. The decoding will simply finish.

When a pt_insn_next call returns pte_eos, does that gurantee that the next call to FindNextSynchronizationPoint will return pte_eos as well?

yes

If so, could this code be changed to immediately return if pte_eos is returned here since currently it will break from the inner loop, go back to the top of the outer loop, call FindNextSynchronizationPoint which will ultimately return pte_eos which causes a break from the outer loop and finally the implicit return from the function? Seems like we could fail fast by immediately returning from the function here if pt_insn_next returns pte_eos.

In this case I don't want to fail fast and instead just break the innermost loop because the code is a little bit big and putting returns in the middle might cause bugs in the future when someone modifies this function. Let's suppose that you add some code right after the big loop thinking that the new code will always be reached. In this case, the early return might unexpectedly finish the execution of the function without reaching your code and you might not easily notice that.

wallace marked 7 inline comments as done.Apr 1 2022, 11:15 AM
wallace updated this revision to Diff 419813.Apr 1 2022, 11:16 AM
  • Address comments
  • Also now using Format instead of Printf, which more idiomatic in this repo.
jj10306 accepted this revision.Apr 1 2022, 2:01 PM

Looks good

lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
248

Do you need .get() or does just *decoded_thread work?