This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Modify the Span API so that Spans propagate with contexts.
ClosedPublic

Authored by sammccall on Jan 24 2018, 12:49 PM.

Details

Summary

This is probably the right behavior for distributed tracers, and makes unpaired
begin-end events impossible without requiring Spans to be bound to a thread.

The API is conceptually clean but syntactically awkward. As discussed offline,
this is basically a naming problem and will go away if (when) we use TLS to
store the current context.

The apparently-unrelated change to onScopeExit are because its move semantics
broken if Func is POD-like since r322838. This is true of function pointers,
and the lambda I use here that captures two pointers only.
I've raised this issue on llvm-dev and will revert this part if we fix it in
some other way.

Diff Detail

Repository
rL LLVM

Event Timeline

sammccall created this revision.Jan 24 2018, 12:49 PM
sammccall updated this revision to Diff 131335.Jan 24 2018, 1:16 PM

Remove obsolete typedef

ilya-biryukov added inline comments.Jan 25 2018, 2:01 AM
clangd/Context.h
163 ↗(On Diff #131335)

s/const &&/&&

165 ↗(On Diff #131335)

This will call the const& version of derive(Key, Value).
To move we need to do std::move(*this).derive(Private, std::forward<Type>(Value))

172 ↗(On Diff #131335)

I wonder what are the use-cases for this operator ==?

clangd/Function.h
147 ↗(On Diff #131335)

Why do we need unique_ptr instead of Optional here?

clangd/Trace.h
92 ↗(On Diff #131335)

This is too easy to misuse unintentionally. Will this go away if we move to thread-local contexts? I.e. will the API leave out mutations of the context that can be used concurrently

I've tried experimenting with that and came up with an alternative that has less changes to the API. Could you take a look, too? D42524

sammccall marked 5 inline comments as done.Jan 25 2018, 7:28 AM

I've tried experimenting with that and came up with an alternative that has less changes to the API. Could you take a look, too? D42524

As discussed offline, I've tried to incorporate the big improvements from there:

  • moved back to Span objects, that for now expose the derived contexts as in your patch (and later will switch the TLS context for their lifetime)
  • SPAN_ATTACH doesn't support the weird lookup that JSONRPCDispatcher uses. Rather than changing that class's traces, I've added locks to support that pattern locally.

Also as discussed offline, The proposed TraceEvent's endSpan/endEvent distinction doesn't seem necessary.
The EventTracer needs to be able to:

  • store some data until the span ends
  • get notified when the span ends

UniqueFunction does provide this, but the interface is slightly confusing: operator() and ~UniqueFunction both denote "when the span ends".
An object with a destructor seems a more natural way to express this, so I've kept that change - I don't feel really strongly though, happy to change this to something else simple.

clangd/Context.h
165 ↗(On Diff #131335)

Oops, good catch!

172 ↗(On Diff #131335)

Sorry, this was dead code from a previous iteration. Removed

clangd/Function.h
147 ↗(On Diff #131335)

ScopeExitGuard was broken by the recent Optional changes (when Func is trivially copyable).
This is a minimal workaround, let's discuss on the other patch.

clangd/Trace.h
92 ↗(On Diff #131335)

This is too easy to misuse unintentionally.

Agreed. I've restored the Span object, and restored the requirement that you pass the span itself to SPAN_ATTACH.

This disallows "action at a distance" that can make for nice traces e.g. for request, but can lead to thread-unsafety.
The only place where we actually use this is JSONRPCDispatcher, so I made that do it explicitly using a lock.
It seems mostly reasonable - if you feel we should remove this feature instead to avoid the complexity, happy to discuss that, but at least it's not in the main tracer interface now.

Will this go away if we move to thread-local contexts? I.e. will the API leave out mutations of the context that can be used concurrently

You've convinced me that requiring the user to pass SPAN_ATTACH to the span makes sense and we should keep it even once we have implicit context passing.

sammccall updated this revision to Diff 131460.Jan 25 2018, 8:27 AM
sammccall marked 4 inline comments as done.
Address review comments
ilya-biryukov accepted this revision.Jan 25 2018, 9:57 AM

LGTM. And sorry for confusion with D42524, if any.

clangd/Function.h
147 ↗(On Diff #131335)

LG, thanks. Wasn't aware of the breakage when writing the comment.

clangd/JSONRPCDispatcher.cpp
31 ↗(On Diff #131460)

We could make the fields private and expose only the function to modify args under lock (similar to FillRequestInfo, i.e. the last two line of it).
That would make the class safer to use. But that's work and the class itself is an implementation detail, so we could also leave it as is.

clangd/Trace.cpp
138 ↗(On Diff #131460)

Would be nice for Spans to have zero cost when no tracer is active. We could probably achieve that be not storing the kSpanArgs when T is null. WDYT?
That's really not a big deal, so I don't think we should block the patch on this.

This revision is now accepted and ready to land.Jan 25 2018, 9:57 AM
sammccall marked 2 inline comments as done.Jan 26 2018, 12:57 AM
sammccall added inline comments.
clangd/JSONRPCDispatcher.cpp
31 ↗(On Diff #131460)

Yeah, good point. Encapsulated the whole mechanism in this class.

clangd/Trace.cpp
138 ↗(On Diff #131460)

Good catch! This was left over from an older revision where SPAN_ATTACH looked up the args in the context.
Now this is for ownership only, so I skip derive() if there's no tracer, and made the key anonymous.

sammccall marked 2 inline comments as done.

Address review comments

This revision was automatically updated to reflect the committed changes.