blob: 75de189b425d6d172d75896e97788808a9ad2fd7 [file] [log] [blame]
Florian Mayer824274d2018-09-17 11:33:45 +01001/*
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#ifndef SRC_PROFILING_MEMORY_CLIENT_H_
18#define SRC_PROFILING_MEMORY_CLIENT_H_
19
Florian Mayer88665be2018-10-03 13:15:38 +010020#include <pthread.h>
Florian Mayer824274d2018-09-17 11:33:45 +010021#include <stddef.h>
Florian Mayeraf266022018-09-17 15:18:15 +010022
Florian Mayereff98042018-12-10 17:44:44 +000023#include <condition_variable>
Florian Mayer824274d2018-09-17 11:33:45 +010024#include <mutex>
25#include <vector>
26
27#include "perfetto/base/scoped_file.h"
Florian Mayerb85a9382018-09-27 13:59:01 +010028#include "src/profiling/memory/wire_protocol.h"
Florian Mayer824274d2018-09-17 11:33:45 +010029
30namespace perfetto {
Florian Mayer8c0d0482018-10-22 14:23:40 +010031namespace profiling {
Florian Mayer824274d2018-09-17 11:33:45 +010032
Florian Mayerb85a9382018-09-27 13:59:01 +010033class BorrowedSocket;
Florian Mayer824274d2018-09-17 11:33:45 +010034
35class SocketPool {
36 public:
37 friend class BorrowedSocket;
38 SocketPool(std::vector<base::ScopedFile> sockets);
39
40 BorrowedSocket Borrow();
Florian Mayer2da28412018-10-30 17:33:10 +000041 void Shutdown();
Florian Mayer824274d2018-09-17 11:33:45 +010042
43 private:
Florian Mayer2da28412018-10-30 17:33:10 +000044 bool shutdown_ = false;
45
Florian Mayer824274d2018-09-17 11:33:45 +010046 void Return(base::ScopedFile fd);
Florian Mayerb85a9382018-09-27 13:59:01 +010047 std::mutex mutex_;
Florian Mayer824274d2018-09-17 11:33:45 +010048 std::condition_variable cv_;
49 std::vector<base::ScopedFile> sockets_;
50 size_t available_sockets_;
Florian Mayeraf266022018-09-17 15:18:15 +010051 size_t dead_sockets_ = 0;
Florian Mayer824274d2018-09-17 11:33:45 +010052};
53
Florian Mayerb85a9382018-09-27 13:59:01 +010054// Socket borrowed from a SocketPool. Gets returned once it goes out of scope.
55class BorrowedSocket {
56 public:
57 BorrowedSocket(const BorrowedSocket&) = delete;
58 BorrowedSocket& operator=(const BorrowedSocket&) = delete;
59 BorrowedSocket(BorrowedSocket&& other) noexcept {
60 fd_ = std::move(other.fd_);
61 socket_pool_ = other.socket_pool_;
62 other.socket_pool_ = nullptr;
63 }
64
65 BorrowedSocket(base::ScopedFile fd, SocketPool* socket_pool)
66 : fd_(std::move(fd)), socket_pool_(socket_pool) {}
67
68 ~BorrowedSocket() {
69 if (socket_pool_ != nullptr)
70 socket_pool_->Return(std::move(fd_));
71 }
72
73 int operator*() { return get(); }
74
75 int get() { return *fd_; }
76
77 void Close() { fd_.reset(); }
78
Florian Mayerf1510c42018-10-17 11:40:52 +010079 operator bool() const { return !!fd_; }
80
Florian Mayerb85a9382018-09-27 13:59:01 +010081 private:
82 base::ScopedFile fd_;
83 SocketPool* socket_pool_ = nullptr;
84};
85
86// Cache for frees that have been observed. It is infeasible to send every
87// free separately, so we batch and send the whole buffer once it is full.
88class FreePage {
89 public:
90 // Add address to buffer. Flush if necessary using a socket borrowed from
91 // pool.
92 // Can be called from any thread. Must not hold mutex_.`
93 void Add(const uint64_t addr, uint64_t sequence_number, SocketPool* pool);
94
95 private:
96 // Needs to be called holding mutex_.
97 void FlushLocked(SocketPool* pool);
98
99 FreeMetadata free_page_;
100 std::mutex mutex_;
101 size_t offset_ = 0;
102};
103
104const char* GetThreadStackBase();
105
Florian Mayer88665be2018-10-03 13:15:38 +0100106// RAII wrapper around pthread_key_t. This is different from a ScopedResource
107// because it needs a separate boolean indicating validity.
108class PThreadKey {
109 public:
110 PThreadKey(const PThreadKey&) = delete;
111 PThreadKey& operator=(const PThreadKey&) = delete;
112
113 PThreadKey(void (*destructor)(void*)) noexcept
114 : valid_(pthread_key_create(&key_, destructor) == 0) {}
115 ~PThreadKey() noexcept {
116 if (valid_)
117 pthread_key_delete(key_);
118 }
119 bool valid() const { return valid_; }
120 pthread_key_t get() const {
121 PERFETTO_DCHECK(valid_);
122 return key_;
123 }
124
125 private:
126 pthread_key_t key_;
127 bool valid_;
128};
129
Florian Mayerb85a9382018-09-27 13:59:01 +0100130// This is created and owned by the malloc hooks.
131class Client {
132 public:
133 Client(std::vector<base::ScopedFile> sockets);
134 Client(const std::string& sock_name, size_t conns);
Florian Mayer9a7fb2b2018-10-17 18:17:40 +0100135 void RecordMalloc(uint64_t alloc_size,
136 uint64_t total_size,
137 uint64_t alloc_address);
Florian Mayerb85a9382018-09-27 13:59:01 +0100138 void RecordFree(uint64_t alloc_address);
Florian Mayer9a7fb2b2018-10-17 18:17:40 +0100139 void MaybeSampleAlloc(uint64_t alloc_size,
140 uint64_t alloc_address,
141 void* (*unhooked_malloc)(size_t),
142 void (*unhooked_free)(void*));
Florian Mayer2da28412018-10-30 17:33:10 +0000143 void Shutdown();
Florian Mayerb85a9382018-09-27 13:59:01 +0100144
Florian Mayer1fe77732018-10-02 17:25:53 +0100145 ClientConfiguration client_config_for_testing() { return client_config_; }
Florian Mayerb12c4f22018-11-14 16:13:02 +0000146 bool inited() { return inited_; }
Florian Mayer1fe77732018-10-02 17:25:53 +0100147
Florian Mayerb85a9382018-09-27 13:59:01 +0100148 private:
Florian Mayer9a7fb2b2018-10-17 18:17:40 +0100149 size_t ShouldSampleAlloc(uint64_t alloc_size,
150 void* (*unhooked_malloc)(size_t),
151 void (*unhooked_free)(void*));
Florian Mayerb85a9382018-09-27 13:59:01 +0100152 const char* GetStackBase();
153
Florian Mayerf0867992018-11-16 10:12:18 +0000154 std::atomic<bool> inited_{false};
Florian Mayer1fe77732018-10-02 17:25:53 +0100155 ClientConfiguration client_config_;
Florian Mayer88665be2018-10-03 13:15:38 +0100156 PThreadKey pthread_key_;
Florian Mayerb85a9382018-09-27 13:59:01 +0100157 SocketPool socket_pool_;
158 FreePage free_page_;
159 const char* main_thread_stack_base_ = nullptr;
160 std::atomic<uint64_t> sequence_number_{0};
161};
162
Florian Mayer8c0d0482018-10-22 14:23:40 +0100163} // namespace profiling
Florian Mayer824274d2018-09-17 11:33:45 +0100164} // namespace perfetto
165
166#endif // SRC_PROFILING_MEMORY_CLIENT_H_