blob: c9cb8b05b4bee388ae3e68a6f4245fa79affcd2d [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 Mayer824274d2018-09-17 11:33:45 +010023#include <mutex>
24#include <vector>
25
26#include "perfetto/base/scoped_file.h"
Florian Mayerb85a9382018-09-27 13:59:01 +010027#include "src/profiling/memory/wire_protocol.h"
Florian Mayer824274d2018-09-17 11:33:45 +010028
29namespace perfetto {
Florian Mayer8c0d0482018-10-22 14:23:40 +010030namespace profiling {
Florian Mayer824274d2018-09-17 11:33:45 +010031
Florian Mayerb85a9382018-09-27 13:59:01 +010032class BorrowedSocket;
Florian Mayer824274d2018-09-17 11:33:45 +010033
34class SocketPool {
35 public:
36 friend class BorrowedSocket;
37 SocketPool(std::vector<base::ScopedFile> sockets);
38
39 BorrowedSocket Borrow();
40
41 private:
42 void Return(base::ScopedFile fd);
Florian Mayerb85a9382018-09-27 13:59:01 +010043 std::mutex mutex_;
Florian Mayer824274d2018-09-17 11:33:45 +010044 std::condition_variable cv_;
45 std::vector<base::ScopedFile> sockets_;
46 size_t available_sockets_;
Florian Mayeraf266022018-09-17 15:18:15 +010047 size_t dead_sockets_ = 0;
Florian Mayer824274d2018-09-17 11:33:45 +010048};
49
Florian Mayerb85a9382018-09-27 13:59:01 +010050// Socket borrowed from a SocketPool. Gets returned once it goes out of scope.
51class BorrowedSocket {
52 public:
53 BorrowedSocket(const BorrowedSocket&) = delete;
54 BorrowedSocket& operator=(const BorrowedSocket&) = delete;
55 BorrowedSocket(BorrowedSocket&& other) noexcept {
56 fd_ = std::move(other.fd_);
57 socket_pool_ = other.socket_pool_;
58 other.socket_pool_ = nullptr;
59 }
60
61 BorrowedSocket(base::ScopedFile fd, SocketPool* socket_pool)
62 : fd_(std::move(fd)), socket_pool_(socket_pool) {}
63
64 ~BorrowedSocket() {
65 if (socket_pool_ != nullptr)
66 socket_pool_->Return(std::move(fd_));
67 }
68
69 int operator*() { return get(); }
70
71 int get() { return *fd_; }
72
73 void Close() { fd_.reset(); }
74
Florian Mayerf1510c42018-10-17 11:40:52 +010075 operator bool() const { return !!fd_; }
76
Florian Mayerb85a9382018-09-27 13:59:01 +010077 private:
78 base::ScopedFile fd_;
79 SocketPool* socket_pool_ = nullptr;
80};
81
82// Cache for frees that have been observed. It is infeasible to send every
83// free separately, so we batch and send the whole buffer once it is full.
84class FreePage {
85 public:
86 // Add address to buffer. Flush if necessary using a socket borrowed from
87 // pool.
88 // Can be called from any thread. Must not hold mutex_.`
89 void Add(const uint64_t addr, uint64_t sequence_number, SocketPool* pool);
90
91 private:
92 // Needs to be called holding mutex_.
93 void FlushLocked(SocketPool* pool);
94
95 FreeMetadata free_page_;
96 std::mutex mutex_;
97 size_t offset_ = 0;
98};
99
100const char* GetThreadStackBase();
101
Florian Mayer88665be2018-10-03 13:15:38 +0100102// RAII wrapper around pthread_key_t. This is different from a ScopedResource
103// because it needs a separate boolean indicating validity.
104class PThreadKey {
105 public:
106 PThreadKey(const PThreadKey&) = delete;
107 PThreadKey& operator=(const PThreadKey&) = delete;
108
109 PThreadKey(void (*destructor)(void*)) noexcept
110 : valid_(pthread_key_create(&key_, destructor) == 0) {}
111 ~PThreadKey() noexcept {
112 if (valid_)
113 pthread_key_delete(key_);
114 }
115 bool valid() const { return valid_; }
116 pthread_key_t get() const {
117 PERFETTO_DCHECK(valid_);
118 return key_;
119 }
120
121 private:
122 pthread_key_t key_;
123 bool valid_;
124};
125
Florian Mayerb85a9382018-09-27 13:59:01 +0100126// This is created and owned by the malloc hooks.
127class Client {
128 public:
129 Client(std::vector<base::ScopedFile> sockets);
130 Client(const std::string& sock_name, size_t conns);
Florian Mayer9a7fb2b2018-10-17 18:17:40 +0100131 void RecordMalloc(uint64_t alloc_size,
132 uint64_t total_size,
133 uint64_t alloc_address);
Florian Mayerb85a9382018-09-27 13:59:01 +0100134 void RecordFree(uint64_t alloc_address);
Florian Mayer9a7fb2b2018-10-17 18:17:40 +0100135 void MaybeSampleAlloc(uint64_t alloc_size,
136 uint64_t alloc_address,
137 void* (*unhooked_malloc)(size_t),
138 void (*unhooked_free)(void*));
Florian Mayerb85a9382018-09-27 13:59:01 +0100139
Florian Mayer1fe77732018-10-02 17:25:53 +0100140 ClientConfiguration client_config_for_testing() { return client_config_; }
141
Florian Mayerb85a9382018-09-27 13:59:01 +0100142 private:
Florian Mayer9a7fb2b2018-10-17 18:17:40 +0100143 size_t ShouldSampleAlloc(uint64_t alloc_size,
144 void* (*unhooked_malloc)(size_t),
145 void (*unhooked_free)(void*));
Florian Mayerb85a9382018-09-27 13:59:01 +0100146 const char* GetStackBase();
147
Florian Mayerf1510c42018-10-17 11:40:52 +0100148 bool inited_ = false;
Florian Mayer1fe77732018-10-02 17:25:53 +0100149 ClientConfiguration client_config_;
Florian Mayer88665be2018-10-03 13:15:38 +0100150 PThreadKey pthread_key_;
Florian Mayerb85a9382018-09-27 13:59:01 +0100151 SocketPool socket_pool_;
152 FreePage free_page_;
153 const char* main_thread_stack_base_ = nullptr;
154 std::atomic<uint64_t> sequence_number_{0};
155};
156
Florian Mayer8c0d0482018-10-22 14:23:40 +0100157} // namespace profiling
Florian Mayer824274d2018-09-17 11:33:45 +0100158} // namespace perfetto
159
160#endif // SRC_PROFILING_MEMORY_CLIENT_H_