aboutsummaryrefslogtreecommitdiff
path: root/include/perfetto/tracing/internal/data_source_internal.h
blob: cb052c64d3351043686226ce4d7e43bea26f692f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*
 * 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_DATA_SOURCE_INTERNAL_H_
#define INCLUDE_PERFETTO_TRACING_INTERNAL_DATA_SOURCE_INTERNAL_H_

#include <stddef.h>
#include <stdint.h>

#include <array>
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>

// No perfetto headers (other than tracing/api and protozero) should be here.
#include "perfetto/tracing/buffer_exhausted_policy.h"
#include "perfetto/tracing/internal/basic_types.h"
#include "perfetto/tracing/trace_writer_base.h"

namespace perfetto {

class DataSourceBase;
class InterceptorBase;
class TraceWriterBase;

namespace internal {

class TracingTLS;

// This maintains the internal state of a data source instance that is used only
// to implement the tracing mechanics and is not exposed to the API client.
// There is one of these object per DataSource instance (up to
// kMaxDataSourceInstances).
struct DataSourceState {
  // This boolean flag determines whether the DataSource::Trace() method should
  // do something or be a no-op. This flag doesn't give the full guarantee
  // that tracing data will be visible in the trace, it just makes it so that
  // the client attemps writing trace data and interacting with the service.
  // For instance, when a tracing session ends the service will reject data
  // commits that arrive too late even if the producer hasn't received the stop
  // IPC message.
  // This flag is set right before calling OnStart() and cleared right before
  // calling OnStop(), unless using HandleStopAsynchronously() (see comments
  // in data_source.h).
  // Keep this flag as the first field. This allows the compiler to directly
  // dereference the DataSourceState* pointer in the trace fast-path without
  // doing extra pointr arithmetic.
  bool trace_lambda_enabled = false;

  // The central buffer id that all TraceWriter(s) created by this data source
  // must target.
  BufferId buffer_id = 0;

  // The index within TracingMuxerImpl.backends_. Practically it allows to
  // lookup the Producer object, and hence the IPC channel, for this data
  // source.
  TracingBackendId backend_id = 0;

  // Each backend may connect to the tracing service multiple times if a
  // disconnection occurs. This counter is used to uniquely identify each
  // connection so that trace writers don't get reused across connections.
  uint32_t backend_connection_id = 0;

  // The instance id as assigned by the tracing service. Note that because a
  // process can be connected to >1 services, this ID is not globally unique but
  // is only unique within the scope of its backend.
  // Only the tuple (backend_id, data_source_instance_id) is globally unique.
  uint64_t data_source_instance_id = 0;

  // A hash of the trace config used by this instance. This is used to
  // de-duplicate instances for data sources with identical names (e.g., track
  // event).
  uint64_t config_hash = 0;

  // If this data source is being intercepted (see Interceptor), this field
  // contains the non-zero id of a registered interceptor which should receive
  // trace packets for this session. Note: interceptor id 1 refers to the first
  // element of TracingMuxerImpl::interceptors_ with successive numbers using
  // the following slots.
  uint32_t interceptor_id = 0;

  // This lock is not held to implement Trace() and it's used only if the trace
  // code wants to access its own data source state.
  // This is to prevent that accessing the data source on an arbitrary embedder
  // thread races with the internal IPC thread destroying the data source
  // because of a end-of-tracing notification from the service.
  // This lock is also used to protect access to a possible interceptor for this
  // data source session.
  std::recursive_mutex lock;
  std::unique_ptr<DataSourceBase> data_source;
  std::unique_ptr<InterceptorBase> interceptor;
};

// This is to allow lazy-initialization and avoid static initializers and
// at-exit destructors. All the entries are initialized via placement-new when
// DataSource::Register() is called, see TracingMuxerImpl::RegisterDataSource().
struct DataSourceStateStorage {
  alignas(DataSourceState) char storage[sizeof(DataSourceState)]{};
};

// Per-DataSource-type global state.
struct DataSourceStaticState {
  // Unique index of the data source, assigned at registration time.
  uint32_t index = kMaxDataSources;

  // A bitmap that tells about the validity of each |instances| entry. When the
  // i-th bit of the bitmap it's set, instances[i] is valid.
  std::atomic<uint32_t> valid_instances{};
  std::array<DataSourceStateStorage, kMaxDataSourceInstances> instances{};

  // Incremented whenever incremental state should be reset for any instance of
  // this data source.
  std::atomic<uint32_t> incremental_state_generation{};

  // Can be used with a cached |valid_instances| bitmap.
  DataSourceState* TryGetCached(uint32_t cached_bitmap, size_t n) {
    return cached_bitmap & (1 << n)
               ? reinterpret_cast<DataSourceState*>(&instances[n])
               : nullptr;
  }

  DataSourceState* TryGet(size_t n) {
    return TryGetCached(valid_instances.load(std::memory_order_acquire), n);
  }

  void CompilerAsserts() {
    static_assert(sizeof(valid_instances.load()) * 8 >= kMaxDataSourceInstances,
                  "kMaxDataSourceInstances too high");
  }
};

// Per-DataSource-instance thread-local state.
struct DataSourceInstanceThreadLocalState {
  using IncrementalStatePointer = std::unique_ptr<void, void (*)(void*)>;

  void Reset() {
    trace_writer.reset();
    incremental_state.reset();
    backend_id = 0;
    backend_connection_id = 0;
    buffer_id = 0;
    data_source_instance_id = 0;
    incremental_state_generation = 0;
    is_intercepted = false;
  }

  std::unique_ptr<TraceWriterBase> trace_writer;
  IncrementalStatePointer incremental_state = {nullptr, [](void*) {}};
  uint32_t incremental_state_generation;
  TracingBackendId backend_id;
  uint32_t backend_connection_id;
  BufferId buffer_id;
  uint64_t data_source_instance_id;
  bool is_intercepted;
};

// Per-DataSource-type thread-local state.
struct DataSourceThreadLocalState {
  DataSourceStaticState* static_state = nullptr;

  // Pointer to the parent tls object that holds us. Used to retrieve the
  // generation, which is per-global-TLS and not per data-source.
  TracingTLS* root_tls = nullptr;

  // One entry per each data source instance.
  std::array<DataSourceInstanceThreadLocalState, kMaxDataSourceInstances>
      per_instance{};
};

}  // namespace internal
}  // namespace perfetto

#endif  // INCLUDE_PERFETTO_TRACING_INTERNAL_DATA_SOURCE_INTERNAL_H_