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