This is an archive of the discontinued LLVM Phabricator instance.

[XRay][compiler-rt] Document and update the XRay Logging API
ClosedPublic

Authored by dberris on Apr 26 2017, 11:04 PM.

Details

Summary

In this patch we document the requirements for implementations that want
to install handlers for the dynamically-controlled XRay "framework".
This clarifies what the expectations are for implementations that
want to install their handlers using this API (similar to how the FDR
logging implementation does so). It also gives users some guarantees on
semantics for the APIs.

If all goes well, users can decide to use the XRay APIs to control the
tracing/logging at the application level, without having to depend on
implementation details of the installed logging implementation. This
lets users choose the implementation that comes with compiler-rt, or
potentially multiple other implementations that use the same APIs.

We also add one convenience function (__xray_remove_log_impl()) for
explicitly removing the currently installed log implementation.

Diff Detail

Repository
rL LLVM

Event Timeline

dberris created this revision.Apr 26 2017, 11:04 PM
kpw edited edge metadata.Apr 27 2017, 2:01 PM

Thanks for thinking this through Dean. Here's a few suggestions I'd like to hear your thoughts on.

include/xray/xray_log_interface.h
15 ↗(On Diff #96866)

Is this comment block intended to show up in Doxygen? I think you'll want an additional slash for these notes.

62 ↗(On Diff #96866)

I suggest a brief word of caution that before patching again, users should call __xray_log_remove_impl and reinitialize. I can see it being a common error that once logs are finalized and/or flushed users think it's OK to patch directly.

For some implementations, it would nice to be able to skip reinitialization. If buffers are already allocated it's a shame to have to remove_impl and reallocate them. Perhaps we should add a __xray_log_reset_impl that by default calls remove_impl and initializes with the same arguments. Log implementations could provide a function ptr to short circuit with appropriate state management.

138–140 ↗(On Diff #96866)

Indicating where readers can find an arg1 installation could be helpful. (xray_interface.h or pointer to fdr logging log_init)

154–157 ↗(On Diff #96866)

It's unclear whether the library prevents this from being called from any particular states.

Let's explicitly point out when this is guaranteed to be safe (no implementation installed and unitialized implementation?), when it is implementation defined, and when it is explicitly disallowed regardless of implementation.

I think it is defined by the implementations when this would be safe to call for an initialized log (or possibly a finalized log).

I can imagine some logging implementations that would want to chain together interceptions. E.g. once I see a request that seeds data for a particular id, install a tracer for subsequent operations that affect the data seeded for the id under inspection.

162–164 ↗(On Diff #96866)

Same comment as for set_impl.

Also, is this a no-op or an error if no implementation is installed?

lib/xray/xray_log_interface.cc
30–38 ↗(On Diff #96866)

Suspicious that the code ignores the return values from xray/xray_interface.h's xray_set_handler" and xray_remove_handler.

Looks like these have to do with checking that xray_init was called.

Should xray_set_log_impl return something other than void? Should implementations call xray_init if necessary?

I'm in favor returning an error rather than hidden runtime cost.

(P.S. lots of underscores missing from function names above. Phabricator was doing markdown stuff with them)

dberris updated this revision to Diff 97033.Apr 27 2017, 7:15 PM
dberris marked 4 inline comments as done.

Address review comments.

include/xray/xray_log_interface.h
15 ↗(On Diff #96866)

Wow, good catch -- yes, otherwise this would be all for nought! :)

62 ↗(On Diff #96866)

Note, that __xray_log_remove_impl() doesn't need to be called at all -- some implementations can be re-initialized just by users directly calling __xray_log_init(...) again. __xray_log_remove_impl() is a "nuclear" option that uninstalls the implementation.

154–157 ↗(On Diff #96866)

Good point. I've extended this to say when it's safe to call and when it's implementation defined.

162–164 ↗(On Diff #96866)

I'm not sure whether mentioning whether it's a no-op is appropriate at this level -- it may be an implementation detail. The side-effect though would be that if there was something installed, then there's no longer something installed. :)

lib/xray/xray_log_interface.cc
30–38 ↗(On Diff #96866)

I thought about whether we should return something for setting the log implementation (or removing it). Because XRay initialisation happens pre-main (see xray_init) and is linked for all xray-instrumented binaries, we let users discover the error when patching.

Semantically, changing the log implementation is not something that can "fail" -- you can set the logging implementation but not be able to patch sleds because there is no instrumentation map. Those two are completely different axes.

Do you have a suggestion on how/where that documentation should show up?

kpw accepted this revision.Apr 28 2017, 9:42 AM
kpw added inline comments.
include/xray/xray_log_interface.h
62 ↗(On Diff #96866)

I missed the state transition from finalized to initializing via xray_log_init. Having that transition serves the same purpose as the proposed xray_log_reset_impl without adding another method.

We might want to point out that this may block on the completion of a flush in the case that the log flush status is XRAY_LOG_FLUSHING.

lib/xray/xray_log_interface.cc
30–38 ↗(On Diff #96866)

I see. Since xray_init is in .preinit_array, I have no problems with swallowing the error codes.

On a related note, do we have to revisit the patch_premain flag? AFAICT, it doesn't allow users to choose their implementation, and more importantly, it doesn't call __xray_log_init. We would have to do something clever to define an interface to have this flag choose the logging implementation. Maybe we could reserve a section header where we can check for user defined function pointers that set up their implementation and if we don't find anything, install and initialize the default.

This revision is now accepted and ready to land.Apr 28 2017, 9:42 AM
dberris marked 3 inline comments as done.Apr 30 2017, 5:50 PM

Thanks @kpw -- landing now, we can iterate on documenting more if things become unclear/confusing.

include/xray/xray_log_interface.h
62 ↗(On Diff #96866)

Yes, we don't need __xray_log_reset_impl() anymore. I thought about that in an early iteration of this API, but decided it's too hard to keep the invariants for that which calling __xray_log_init() already achieves.

__xray_log_remove_impl() does something very different though. It literally removes the implementation that's currently installed.

lib/xray/xray_log_interface.cc
30–38 ↗(On Diff #96866)

We let users choose the implementation for patch_premain by letting users define either xray_naive_log= or xray_fdr_log=. This API allows users to install an implementation that can't be installed through the flags. It's also for controlling an implementation explicitly (init, finalize, flush, repeat).

We might want to consider an explicit registration/initialisation mechanism, but users can already do this at init-time, by doing a global initializer that runs before main() but after premain.

This revision was automatically updated to reflect the committed changes.
dberris marked an inline comment as done.