blob: 5bcfff5dbc6808f83b29ae97af84112ffddb13db [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
20#include <stddef.h>
Florian Mayeraf266022018-09-17 15:18:15 +010021
Ryan Savitskia502bde2019-02-26 21:34:03 +000022#include <atomic>
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
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010027#include "perfetto/base/unix_socket.h"
Ryan Savitskia502bde2019-02-26 21:34:03 +000028#include "src/profiling/memory/sampler.h"
Florian Mayerb85a9382018-09-27 13:59:01 +010029#include "src/profiling/memory/wire_protocol.h"
Florian Mayer824274d2018-09-17 11:33:45 +010030
31namespace perfetto {
Florian Mayer8c0d0482018-10-22 14:23:40 +010032namespace profiling {
Florian Mayer824274d2018-09-17 11:33:45 +010033
Florian Mayerb85a9382018-09-27 13:59:01 +010034class BorrowedSocket;
Florian Mayer824274d2018-09-17 11:33:45 +010035
36class SocketPool {
37 public:
38 friend class BorrowedSocket;
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010039 SocketPool(std::vector<base::UnixSocketRaw> sockets);
Florian Mayer824274d2018-09-17 11:33:45 +010040
41 BorrowedSocket Borrow();
Florian Mayer2da28412018-10-30 17:33:10 +000042 void Shutdown();
Florian Mayer824274d2018-09-17 11:33:45 +010043
44 private:
Florian Mayer2da28412018-10-30 17:33:10 +000045 bool shutdown_ = false;
46
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010047 void Return(base::UnixSocketRaw);
Florian Mayer65081572018-12-18 13:41:08 +000048 std::timed_mutex mutex_;
49 std::condition_variable_any cv_;
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010050 std::vector<base::UnixSocketRaw> sockets_;
Florian Mayer824274d2018-09-17 11:33:45 +010051 size_t available_sockets_;
Florian Mayeraf266022018-09-17 15:18:15 +010052 size_t dead_sockets_ = 0;
Florian Mayer824274d2018-09-17 11:33:45 +010053};
54
Florian Mayerb85a9382018-09-27 13:59:01 +010055// Socket borrowed from a SocketPool. Gets returned once it goes out of scope.
56class BorrowedSocket {
57 public:
58 BorrowedSocket(const BorrowedSocket&) = delete;
59 BorrowedSocket& operator=(const BorrowedSocket&) = delete;
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010060 BorrowedSocket(BorrowedSocket&& other) noexcept
61 : sock_(std::move(other.sock_)), socket_pool_(other.socket_pool_) {
Florian Mayerb85a9382018-09-27 13:59:01 +010062 other.socket_pool_ = nullptr;
63 }
64
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010065 BorrowedSocket(base::UnixSocketRaw sock, SocketPool* socket_pool)
66 : sock_(std::move(sock)), socket_pool_(socket_pool) {}
Florian Mayerb85a9382018-09-27 13:59:01 +010067
68 ~BorrowedSocket() {
69 if (socket_pool_ != nullptr)
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010070 socket_pool_->Return(std::move(sock_));
Florian Mayerb85a9382018-09-27 13:59:01 +010071 }
72
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010073 base::UnixSocketRaw* operator->() { return &sock_; }
74 base::UnixSocketRaw* get() { return &sock_; }
75 void Shutdown() { sock_.Shutdown(); }
76 explicit operator bool() const { return !!sock_; }
Florian Mayerf1510c42018-10-17 11:40:52 +010077
Florian Mayerb85a9382018-09-27 13:59:01 +010078 private:
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010079 base::UnixSocketRaw sock_;
Florian Mayerb85a9382018-09-27 13:59:01 +010080 SocketPool* socket_pool_ = nullptr;
81};
82
83// Cache for frees that have been observed. It is infeasible to send every
84// free separately, so we batch and send the whole buffer once it is full.
85class FreePage {
86 public:
Florian Mayer192136e2019-01-30 18:04:34 +000087 FreePage(uint64_t client_generation) {
88 free_page_.client_generation = client_generation;
89 }
90
Florian Mayerb85a9382018-09-27 13:59:01 +010091 // Add address to buffer. Flush if necessary using a socket borrowed from
92 // pool.
Ryan Savitskia502bde2019-02-26 21:34:03 +000093 // Can be called from any thread. Must not hold mutex_.
Florian Mayer65081572018-12-18 13:41:08 +000094 bool Add(const uint64_t addr, uint64_t sequence_number, SocketPool* pool);
Florian Mayerb85a9382018-09-27 13:59:01 +010095
96 private:
97 // Needs to be called holding mutex_.
Florian Mayer65081572018-12-18 13:41:08 +000098 bool FlushLocked(SocketPool* pool);
Florian Mayerb85a9382018-09-27 13:59:01 +010099
100 FreeMetadata free_page_;
Florian Mayer65081572018-12-18 13:41:08 +0000101 std::timed_mutex mutex_;
Florian Mayerb85a9382018-09-27 13:59:01 +0100102 size_t offset_ = 0;
103};
104
105const char* GetThreadStackBase();
106
Florian Mayerdac31272019-02-26 12:07:02 +0000107constexpr uint32_t kClientSockTimeoutMs = 1000;
Ryan Savitski14c12d62019-01-08 22:38:53 +0000108
Ryan Savitskia502bde2019-02-26 21:34:03 +0000109// Profiling client, used to sample and record the malloc/free family of calls,
110// and communicate the necessary state to a separate profiling daemon process.
111//
112// Created and owned by the malloc hooks.
113//
114// Methods of this class are thread-safe unless otherwise stated, in which case
115// the caller needs to synchronize calls behind a mutex or similar.
Florian Mayerb85a9382018-09-27 13:59:01 +0100116class Client {
117 public:
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100118 Client(std::vector<base::UnixSocketRaw> sockets);
Florian Mayerb85a9382018-09-27 13:59:01 +0100119 Client(const std::string& sock_name, size_t conns);
Florian Mayer20c4b3c2019-01-24 18:25:35 +0000120 bool RecordMalloc(uint64_t alloc_size,
Florian Mayer9a7fb2b2018-10-17 18:17:40 +0100121 uint64_t total_size,
122 uint64_t alloc_address);
Florian Mayer20c4b3c2019-01-24 18:25:35 +0000123 bool RecordFree(uint64_t alloc_address);
Florian Mayer2da28412018-10-30 17:33:10 +0000124 void Shutdown();
Florian Mayerb85a9382018-09-27 13:59:01 +0100125
Ryan Savitskia502bde2019-02-26 21:34:03 +0000126 // Returns the number of bytes to assign to an allocation with the given
127 // |alloc_size|, based on the current sampling rate. A return value of zero
128 // means that the allocation should not be recorded. Not idempotent, each
129 // invocation mutates the sampler state.
130 //
131 // Not thread-safe.
132 size_t GetSampleSizeLocked(size_t alloc_size) {
133 if (!inited_.load(std::memory_order_acquire))
134 return 0;
135 return sampler_.SampleSize(alloc_size);
136 }
137
Florian Mayer1fe77732018-10-02 17:25:53 +0100138 ClientConfiguration client_config_for_testing() { return client_config_; }
Florian Mayerb12c4f22018-11-14 16:13:02 +0000139 bool inited() { return inited_; }
Florian Mayer1fe77732018-10-02 17:25:53 +0100140
Florian Mayerb85a9382018-09-27 13:59:01 +0100141 private:
142 const char* GetStackBase();
143
Florian Mayer192136e2019-01-30 18:04:34 +0000144 static std::atomic<uint64_t> max_generation_;
145 const uint64_t generation_;
146
Ryan Savitskia502bde2019-02-26 21:34:03 +0000147 // TODO(rsavitski): used to check if the client is completely initialized
148 // after construction. The reads in RecordFree & GetSampleSizeLocked are no
149 // longer necessary (was an optimization to not do redundant work after
150 // shutdown). Turn into a normal bool, or indicate construction failures
151 // differently.
Florian Mayerf0867992018-11-16 10:12:18 +0000152 std::atomic<bool> inited_{false};
Florian Mayer1fe77732018-10-02 17:25:53 +0100153 ClientConfiguration client_config_;
Ryan Savitskia502bde2019-02-26 21:34:03 +0000154 // sampler_ operations are not thread-safe.
155 Sampler sampler_;
Florian Mayerb85a9382018-09-27 13:59:01 +0100156 SocketPool socket_pool_;
157 FreePage free_page_;
158 const char* main_thread_stack_base_ = nullptr;
159 std::atomic<uint64_t> sequence_number_{0};
160};
161
Florian Mayer8c0d0482018-10-22 14:23:40 +0100162} // namespace profiling
Florian Mayer824274d2018-09-17 11:33:45 +0100163} // namespace perfetto
164
165#endif // SRC_PROFILING_MEMORY_CLIENT_H_