1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef INCLUDE_PERFETTO_TRACING_INTERNAL_TRACING_TLS_H_ 18 #define INCLUDE_PERFETTO_TRACING_INTERNAL_TRACING_TLS_H_ 19 20 #include <array> 21 #include <memory> 22 23 #include "perfetto/tracing/internal/basic_types.h" 24 #include "perfetto/tracing/internal/data_source_internal.h" 25 #include "perfetto/tracing/platform.h" 26 27 namespace perfetto { 28 29 class TraceWriterBase; 30 31 namespace internal { 32 33 // Organization of the thread-local storage 34 // ---------------------------------------- 35 // First of all, remember the cardinality of the problem: at any point in time 36 // there are M data sources registered (i.e. number of subclasses of DataSource) 37 // and up to N concurrent instances for each data source, so up to M * N total 38 // data source instances around. 39 // Each data source instance can be accessed by T threads (no upper bound). 40 // We can safely put hard limits both to M and N (i.e. say that we support at 41 // most 32 data source types per process and up to 8 concurrent instances). 42 // 43 // We want to make it so from the Platform viewpoint, we use only one global 44 // TLS object, so T instances in total, one per thread, regardless of M and N. 45 // This allows to deal with at-thread-exit destruction only in one place, rather 46 // than N, M or M * N. 47 // 48 // Visually: 49 // [ Thread 1 ] [ Thread 2 ] [ Thread T ] 50 // +---------------+ +---------------+ +---------------+ 51 // Data source Foo | | | | | | 52 // Instance 1 | TLS | | TLS | | TLS | 53 // Instance 2 | Object | | Object | | Object | 54 // Instance 3 | | | | | | 55 // | | | | | | 56 // Data source Bar | | | | | | 57 // Instance 1 | | | | | | 58 // Instance 2 | | | | | | 59 // +---------------+ +---------------+ +---------------+ 60 // 61 // Each TLS Object is organized as an array of M DataSourceThreadLocalState. 62 // Each DSTLS itself is an array of up to N per-instance objects. 63 // The only per-instance object for now is the TraceWriter. 64 // So for each data source, for each instance, for each thread we keep one 65 // TraceWriter. 66 // The lookup is O(1): Given the TLS object, the TraceWriter is just tls[M][N]. 67 class TracingTLS : public Platform::ThreadLocalObject { 68 public: 69 ~TracingTLS() override; 70 71 // This is checked against TraceMuxerImpl's global generation counter to 72 // handle destruction of TraceWriter(s) that belong to data sources that 73 // have been stopped. When the two numbers diverge, a scan of all the 74 // thread-local TraceWriter(s) is issued. 75 uint32_t generation = 0; 76 77 // This flag is true while this thread is inside a trace point for any data 78 // source or in other delicate parts of the tracing machinery during which we 79 // should not try to trace. Used to prevent unexpected re-entrancy. 80 bool is_in_trace_point = false; 81 82 // By default all data source instances have independent thread-local state 83 // (see above). 84 std::array<DataSourceThreadLocalState, kMaxDataSources> data_sources_tls{}; 85 86 // Track event data sources, however, share the same thread-local state in 87 // order to be able to share trace writers and interning state across all 88 // track event categories. 89 DataSourceThreadLocalState track_event_tls{}; 90 }; 91 92 struct ScopedReentrancyAnnotator { ScopedReentrancyAnnotatorScopedReentrancyAnnotator93 ScopedReentrancyAnnotator(TracingTLS& root_tls) : root_tls_(root_tls) { 94 PERFETTO_DCHECK(!root_tls_.is_in_trace_point); 95 root_tls_.is_in_trace_point = true; 96 } ~ScopedReentrancyAnnotatorScopedReentrancyAnnotator97 ~ScopedReentrancyAnnotator() { root_tls_.is_in_trace_point = false; } 98 99 private: 100 TracingTLS& root_tls_; 101 }; 102 103 } // namespace internal 104 } // namespace perfetto 105 106 #endif // INCLUDE_PERFETTO_TRACING_INTERNAL_TRACING_TLS_H_ 107