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