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