blob: dc3a7b6dc5f427080edfc6ff7cc67551edda7b2a [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef INCLUDE_PERFETTO_TRACING_INTERNAL_TRACING_TLS_H_
#define INCLUDE_PERFETTO_TRACING_INTERNAL_TRACING_TLS_H_
#include <array>
#include <memory>
#include "perfetto/tracing/internal/basic_types.h"
#include "perfetto/tracing/internal/data_source_internal.h"
#include "perfetto/tracing/platform.h"
namespace perfetto {
class TraceWriterBase;
namespace internal {
// Organization of the thread-local storage
// ----------------------------------------
// First of all, remember the cardinality of the problem: at any point in time
// there are M data sources registered (i.e. number of subclasses of DataSource)
// and up to N concurrent instances for each data source, so up to M * N total
// data source instances around.
// Each data source instance can be accessed by T threads (no upper bound).
// We can safely put hard limits both to M and N (i.e. say that we support at
// most 32 data source types per process and up to 8 concurrent instances).
//
// We want to make it so from the Platform viewpoint, we use only one global
// TLS object, so T instances in total, one per thread, regardless of M and N.
// This allows to deal with at-thread-exit destruction only in one place, rather
// than N, M or M * N.
//
// Visually:
// [ Thread 1 ] [ Thread 2 ] [ Thread T ]
// +---------------+ +---------------+ +---------------+
// Data source Foo | | | | | |
// Instance 1 | TLS | | TLS | | TLS |
// Instance 2 | Object | | Object | | Object |
// Instance 3 | | | | | |
// | | | | | |
// Data source Bar | | | | | |
// Instance 1 | | | | | |
// Instance 2 | | | | | |
// +---------------+ +---------------+ +---------------+
//
// Each TLS Object is organized as an array of M DataSourceThreadLocalState.
// Each DSTLS itself is an array of up to N per-instance objects.
// The only per-instance object for now is the TraceWriter.
// So for each data source, for each instance, for each thread we keep one
// TraceWriter.
// The lookup is O(1): Given the TLS object, the TraceWriter is just tls[M][N].
class TracingTLS : public Platform::ThreadLocalObject {
public:
~TracingTLS() override;
// This is checked against TraceMuxerImpl's global generation counter to
// handle destruction of TraceWriter(s) that belong to data sources that
// have been stopped. When the two numbers diverge, a scan of all the
// thread-local TraceWriter(s) is issued.
uint32_t generation = 0;
// This flag is true while this thread is inside a trace point for any data
// source or in other delicate parts of the tracing machinery during which we
// should not try to trace. Used to prevent unexpected re-entrancy.
// This flag is also load-bearing when handling re-entrancy during thread-exit
// handlers. See comment in TracingTLS::~TracingTLS().
bool is_in_trace_point = false;
// Used inside a trace point (only one trace point per thread can be active at
// any time) to cache the instances bitmap.
uint32_t cached_instances = 0;
// By default all data source instances have independent thread-local state
// (see above).
std::array<DataSourceThreadLocalState, kMaxDataSources> data_sources_tls{};
// Track event data sources, however, share the same thread-local state in
// order to be able to share trace writers and interning state across all
// track event categories.
DataSourceThreadLocalState track_event_tls{};
};
struct ScopedReentrancyAnnotator {
ScopedReentrancyAnnotator(TracingTLS& root_tls) : root_tls_(root_tls) {
PERFETTO_DCHECK(!root_tls_.is_in_trace_point);
root_tls_.is_in_trace_point = true;
}
~ScopedReentrancyAnnotator() { root_tls_.is_in_trace_point = false; }
private:
TracingTLS& root_tls_;
};
} // namespace internal
} // namespace perfetto
#endif // INCLUDE_PERFETTO_TRACING_INTERNAL_TRACING_TLS_H_