• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 // The data types used for communication between heapprofd and the client
18 // embedded in processes that are being profiled.
19 
20 #ifndef SRC_PROFILING_MEMORY_WIRE_PROTOCOL_H_
21 #define SRC_PROFILING_MEMORY_WIRE_PROTOCOL_H_
22 
23 #include <cinttypes>
24 
25 #include <unwindstack/Elf.h>
26 #include <unwindstack/MachineArm.h>
27 #include <unwindstack/MachineArm64.h>
28 #include <unwindstack/MachineMips.h>
29 #include <unwindstack/MachineMips64.h>
30 #include <unwindstack/MachineX86.h>
31 #include <unwindstack/MachineX86_64.h>
32 
33 #include "perfetto/heap_profile.h"
34 #include "src/profiling/memory/shared_ring_buffer.h"
35 #include "src/profiling/memory/util.h"
36 
37 namespace perfetto {
38 
39 namespace base {
40 class UnixSocketRaw;
41 }
42 
43 namespace profiling {
44 
45 // C++11 std::max is not constexpr.
constexpr_max(size_t x,size_t y)46 constexpr size_t constexpr_max(size_t x, size_t y) {
47   return x > y ? x : y;
48 }
49 
50 // clang-format makes this unreadable. Turning it off for this block.
51 // clang-format off
52 constexpr size_t kMaxRegisterDataSize =
53   constexpr_max(
54     constexpr_max(
55       constexpr_max(
56         constexpr_max(
57             constexpr_max(
58               sizeof(uint32_t) * unwindstack::ARM_REG_LAST,
59               sizeof(uint64_t) * unwindstack::ARM64_REG_LAST),
60             sizeof(uint32_t) * unwindstack::X86_REG_LAST),
61           sizeof(uint64_t) * unwindstack::X86_64_REG_LAST),
62         sizeof(uint32_t) * unwindstack::MIPS_REG_LAST),
63       sizeof(uint64_t) * unwindstack::MIPS64_REG_LAST
64   );
65 // clang-format on
66 
67 // Types needed for the wire format used for communication between the client
68 // and heapprofd. The basic format of a record sent by the client is
69 // record size (uint64_t) | record type (RecordType = uint64_t) | record
70 // If record type is Malloc, the record format is AllocMetdata | raw stack.
71 // If the record type is Free, the record is a FreeEntry.
72 // If record type is HeapName, the record is a HeapName.
73 // On connect, heapprofd sends one ClientConfiguration struct over the control
74 // socket.
75 
76 // Use uint64_t to make sure the following data is aligned as 64bit is the
77 // strongest alignment requirement.
78 
79 struct ClientConfigurationHeap {
80   char name[HEAPPROFD_HEAP_NAME_SZ];
81   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) interval;
82 };
83 
84 struct ClientConfiguration {
85   // On average, sample one allocation every interval bytes,
86   // If interval == 1, sample every allocation.
87   // Must be >= 1.
88   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) default_interval;
89   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) block_client_timeout_us;
90   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) num_heaps;
91   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) adaptive_sampling_shmem_threshold;
92   PERFETTO_CROSS_ABI_ALIGNED(uint64_t)
93   adaptive_sampling_max_sampling_interval_bytes;
94   alignas(8) ClientConfigurationHeap heaps[64];
95   PERFETTO_CROSS_ABI_ALIGNED(bool) block_client;
96   PERFETTO_CROSS_ABI_ALIGNED(bool) disable_fork_teardown;
97   PERFETTO_CROSS_ABI_ALIGNED(bool) disable_vfork_detection;
98   PERFETTO_CROSS_ABI_ALIGNED(bool) all_heaps;
99   // Just double check that the array sizes are in correct order.
100 };
101 
102 enum class RecordType : uint64_t {
103   Free = 0,
104   Malloc = 1,
105   HeapName = 2,
106 };
107 
108 // Make the whole struct 8-aligned. This is to make sizeof(AllocMetdata)
109 // the same on 32 and 64-bit.
110 struct alignas(8) AllocMetadata {
111   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) sequence_number;
112   // Size of the allocation that was made.
113   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) alloc_size;
114   // Total number of bytes attributed to this allocation.
115   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) sample_size;
116   // Pointer returned by malloc(2) for this allocation.
117   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) alloc_address;
118   // Current value of the stack pointer.
119   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) stack_pointer;
120   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) clock_monotonic_coarse_timestamp;
121   // unwindstack::AsmGetRegs assumes this is aligned.
122   alignas(8) char register_data[kMaxRegisterDataSize];
123   PERFETTO_CROSS_ABI_ALIGNED(uint32_t) heap_id;
124   // CPU architecture of the client.
125   PERFETTO_CROSS_ABI_ALIGNED(unwindstack::ArchEnum) arch;
126 };
127 
128 struct FreeEntry {
129   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) sequence_number;
130   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) addr;
131   PERFETTO_CROSS_ABI_ALIGNED(uint32_t) heap_id;
132 };
133 
134 struct HeapName {
135   PERFETTO_CROSS_ABI_ALIGNED(uint64_t) sample_interval;
136   PERFETTO_CROSS_ABI_ALIGNED(uint32_t) heap_id;
137   PERFETTO_CROSS_ABI_ALIGNED(char) heap_name[HEAPPROFD_HEAP_NAME_SZ];
138 };
139 
140 // Make sure the sizes do not change on different architectures.
141 static_assert(sizeof(AllocMetadata) == 328,
142               "AllocMetadata needs to be the same size across ABIs.");
143 static_assert(sizeof(FreeEntry) == 24,
144               "FreeEntry needs to be the same size across ABIs.");
145 static_assert(sizeof(HeapName) == 80,
146               "HeapName needs to be the same size across ABIs.");
147 static_assert(sizeof(ClientConfiguration) == 4656,
148               "ClientConfiguration needs to be the same size across ABIs.");
149 
150 enum HandshakeFDs : size_t {
151   kHandshakeMaps = 0,
152   kHandshakeMem,
153   kHandshakeSize,
154 };
155 
156 struct WireMessage {
157   RecordType record_type;
158 
159   AllocMetadata* alloc_header;
160   FreeEntry* free_header;
161   HeapName* heap_name_header;
162 
163   char* payload;
164   size_t payload_size;
165 };
166 
167 int64_t SendWireMessage(SharedRingBuffer* buf, const WireMessage& msg);
168 
169 // Parse message received over the wire.
170 // |buf| has to outlive |out|.
171 // If buf is not a valid message, return false.
172 bool ReceiveWireMessage(char* buf, size_t size, WireMessage* out);
173 
174 uint64_t GetHeapSamplingInterval(const ClientConfiguration& cli_config,
175                                  const char* heap_name);
176 
177 constexpr const char* kHeapprofdSocketEnvVar = "ANDROID_SOCKET_heapprofd";
178 constexpr const char* kHeapprofdSocketFile = "/dev/socket/heapprofd";
179 
180 }  // namespace profiling
181 }  // namespace perfetto
182 
183 #endif  // SRC_PROFILING_MEMORY_WIRE_PROTOCOL_H_
184