Descriptiontracing: simplify lifetime of TraceEventFilter(s)
Two major changes introduced by this CL, both aimed at reducing the
complexity of TraceLog:
1) Simplify the lifetime of TraceEventFilters. Now they are kept alive
until the very last moment when there is no space left for other
filters.
2) Don't cache the full TraceConfig::EventFilters in the TraceLog.
Instead make each filter keep its own copy of its config.
Background: TraceLog modes (recording, filtering, both)
-------------------------------------------------------
Recent changes (crrev.com/{2323483005,2316403002,2259493003) added the
ability to have two modes for TraceLog: recording, filtering or both.
"Recording" is the conventional mode where the macros
TRACE_EVENT*(category, event, args...) directly inject events into the
trace buffer when the corresponding category is enabled.
"Filtering" alone turns on the macros without recording events in
the buffer, but allows filters to snoop the events. A concrete
use case for this mode is the --enable-heap-profiling mode which
wants to see all the TRACE_EVENTs to reconstruct the pseudo stack
but doesn't want them to fill the trace buffer.
It is also possible to combine the two modes (filtering + recording).
In this case the filters have also the power of preventing an event
to be added to the buffer. The use case here (not there yet in the code)
are the cases where we want to collect traces form the field but want
to limit the size of the trace by doing some fine grained stripping.
Side note: there is a further level of filtering in TraceLog called
ArgumentFilterPredicate. Today this is used for post-processing the
buffer before flushing to filter out PII-sensitive events. Perhaps
in the near future this could be merged with the filtering mode.
However this is out of scope from this CL.
Problem: duplication of TraceConfig in TraceLog
-----------------------------------------------
The way TraceLog today handles multiple modes is quite hard to follow.
TraceLog today has one copy of the TraceConfig (which can contain config
for both modes) but two states (recording and filtering).
To overcome this, TraceLog keeps also a cached copy of the parts of
TraceConfig relevant for filters in the |enabled_event_filters_| field
and strives to keep that in sync with the indexed in the bitmaps of the
TraceCategory classes.
Solution introduced by this CL:
TraceLog stops keeping a cached copy of the TraceConfig. Instead
when creating and registering a filter, it attaches the config of the
specific filter to the filter instance itself. This can be obtained
without coupling TraceEventFilter and TraceConfig by using a tiny
interface with one virtual method (see TraceEventFilter::Config).
Overall this makes TraceLog simpler and easier to reason about filters.
Problem: lifetime of TraceEventFilter(s)
----------------------------------------
When is it safe to destroy a TraceEventFilter? They can be *disabled*
but not *destroyed* immediately after TraceLog::SetDisabled(FILTERING).
This is because of the multi-threading nature of tracing: other threads
might still be referencing the filters while tracing is being disabled.
Using a lock is a no-go as we don't want tracing to serialize the various
threads around a lock.
The current approach destroys them when tracing is re-enabled. This
can still causes races though if tracing is disabled and immediately
re-enabled. Also this makes the TraceLog code hard to follow.
Solution introduced by this CL:
When a new filter is registered, The EventFilterRegistry (EFR) adds it
to the set of filters (or crashes if there are no slots left).
The filter can be referred to via a numeric index which is guaranteed to
be stable for all the lifetime of the filter. This index is used by the
TraceCategory.enabled_filters_ bitmap.
When a filter is not needed anymore TraceLog simply unregisters it and
stops caring about its lifetime. The EFT will NOT destroy it immediately.
Instead it will mark it as free-able and defer the destruction until the
very last moment, that is, after unregistering all filters and adding other
32 of them. This makes the race extremely unrealistic at this point. The
only case when a thread can still refer to a destroyed filter becomes the
interval between starting the execution of a TRACE_EVENTx macro (when
the enabled_filters_ bitmap is read) and the invocation of the filter
(few instructions afterwards). In this tiny interval tracing needs to
be stopped and started enough times to add other 32 filters in order to
hit the race. Which is technically still possible but becomes
extremely unlikely from a practical viewpoint.
BUG=659689
Patch Set 1 #Patch Set 2 : . #Patch Set 3 : . #Patch Set 4 : rebase #Patch Set 5 : rebase #Patch Set 6 : rebase #
Total comments: 16
Depends on Patchset: Messages
Total messages: 34 (26 generated)
|