/*
* Copyright (C) 2018 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.
*/
// The data types used for communication between heapprofd and the client
// embedded in processes that are being profiled.
#ifndef SRC_PROFILING_MEMORY_WIRE_PROTOCOL_H_
#define SRC_PROFILING_MEMORY_WIRE_PROTOCOL_H_
#include <inttypes.h>
#include <unwindstack/Elf.h>
#include <unwindstack/UserArm.h>
#include <unwindstack/UserArm64.h>
#include <unwindstack/UserMips.h>
#include <unwindstack/UserMips64.h>
#include <unwindstack/UserX86.h>
#include <unwindstack/UserX86_64.h>
#include "src/profiling/memory/shared_ring_buffer.h"
namespace perfetto {
namespace base {
class UnixSocketRaw;
}
namespace profiling {
struct ClientConfiguration {
// On average, sample one allocation every interval bytes,
// If interval == 1, sample every allocation.
// Must be >= 1.
uint64_t interval;
bool block_client;
};
// Types needed for the wire format used for communication between the client
// and heapprofd. The basic format of a record is
// record size (uint64_t) | record type (RecordType = uint64_t) | record
// If record type is malloc, the record format is AllocMetdata | raw stack.
// If the record type is free, the record is a sequence of FreeBatchEntry.
// Use uint64_t to make sure the following data is aligned as 64bit is the
// strongest alignment requirement.
// C++11 std::max is not constexpr.
constexpr size_t constexpr_max(size_t x, size_t y) {
return x > y ? x : y;
}
// clang-format makes this unreadable. Turning it off for this block.
// clang-format off
constexpr size_t kMaxRegisterDataSize =
constexpr_max(
constexpr_max(
constexpr_max(
constexpr_max(
constexpr_max(
sizeof(unwindstack::arm_user_regs),
sizeof(unwindstack::arm64_user_regs)),
sizeof(unwindstack::x86_user_regs)),
sizeof(unwindstack::x86_64_user_regs)),
sizeof(unwindstack::mips_user_regs)),
sizeof(unwindstack::mips64_user_regs)
);
// clang-format on
constexpr size_t kFreeBatchSize = 1024;
enum class RecordType : uint64_t {
Free = 0,
Malloc = 1,
};
struct AllocMetadata {
uint64_t sequence_number;
// Size of the allocation that was made.
uint64_t alloc_size;
// Total number of bytes attributed to this allocation.
uint64_t total_size;
// Pointer returned by malloc(2) for this allocation.
uint64_t alloc_address;
// Current value of the stack pointer.
uint64_t stack_pointer;
// Offset of the data at stack_pointer from the start of this record.
uint64_t stack_pointer_offset;
uint64_t clock_monotonic_coarse_timestamp;
alignas(uint64_t) char register_data[kMaxRegisterDataSize];
// CPU architecture of the client. This determines the size of the
// register data that follows this struct.
unwindstack::ArchEnum arch;
};
struct FreeBatchEntry {
uint64_t sequence_number;
uint64_t addr;
};
struct FreeBatch {
uint64_t num_entries;
uint64_t clock_monotonic_coarse_timestamp;
FreeBatchEntry entries[kFreeBatchSize];
FreeBatch() { num_entries = 0; }
};
enum HandshakeFDs : size_t {
kHandshakeMaps = 0,
kHandshakeMem = 1,
kHandshakeSize = 2,
};
struct WireMessage {
RecordType record_type;
AllocMetadata* alloc_header;
FreeBatch* free_header;
char* payload;
size_t payload_size;
};
bool SendWireMessage(SharedRingBuffer* buf, const WireMessage& msg);
// Parse message received over the wire.
// |buf| has to outlive |out|.
// If buf is not a valid message, return false.
bool ReceiveWireMessage(char* buf, size_t size, WireMessage* out);
constexpr const char* kHeapprofdSocketEnvVar = "ANDROID_SOCKET_heapprofd";
constexpr const char* kHeapprofdSocketFile = "/dev/socket/heapprofd";
} // namespace profiling
} // namespace perfetto
#endif // SRC_PROFILING_MEMORY_WIRE_PROTOCOL_H_