profiling: Add FreePage.
Change-Id: If77bdfd16fdba39acf532706a9e8b621d88a4c96
diff --git a/src/profiling/memory/client.cc b/src/profiling/memory/client.cc
index d0e8f61..f8d57f7 100644
--- a/src/profiling/memory/client.cc
+++ b/src/profiling/memory/client.cc
@@ -26,6 +26,48 @@
#include "src/profiling/memory/transport_data.h"
namespace perfetto {
+namespace {
+
+std::atomic<uint64_t> global_sequence_number(0);
+constexpr size_t kFreePageBytes = base::kPageSize;
+constexpr size_t kFreePageSize = kFreePageBytes / sizeof(uint64_t);
+
+} // namespace
+
+FreePage::FreePage() : free_page_(kFreePageSize) {
+ free_page_[0] = static_cast<uint64_t>(kFreePageBytes);
+ free_page_[1] = static_cast<uint64_t>(RecordType::Free);
+ offset_ = 2;
+ // Code in Add assumes that offset is aligned to 2.
+ PERFETTO_DCHECK(offset_ % 2 == 0);
+}
+
+void FreePage::Add(const uint64_t addr, SocketPool* pool) {
+ std::lock_guard<std::mutex> l(mtx_);
+ if (offset_ == kFreePageSize)
+ Flush(pool);
+ static_assert(kFreePageSize % 2 == 0,
+ "free page size needs to be divisible by two");
+ free_page_[offset_++] = ++global_sequence_number;
+ free_page_[offset_++] = addr;
+ PERFETTO_DCHECK(offset_ % 2 == 0);
+}
+
+void FreePage::Flush(SocketPool* pool) {
+ BorrowedSocket fd(pool->Borrow());
+ size_t written = 0;
+ do {
+ ssize_t wr = PERFETTO_EINTR(send(*fd, &free_page_[0] + written,
+ kFreePageBytes - written, MSG_NOSIGNAL));
+ if (wr == -1) {
+ fd.Close();
+ return;
+ }
+ written += static_cast<size_t>(wr);
+ } while (written < kFreePageBytes);
+ // Now that we have flushed, reset to after the header.
+ offset_ = 2;
+}
BorrowedSocket::BorrowedSocket(base::ScopedFile fd, SocketPool* socket_pool)
: fd_(std::move(fd)), socket_pool_(socket_pool) {}
@@ -59,6 +101,12 @@
}
void SocketPool::Return(base::ScopedFile sock) {
+ if (!sock) {
+ // TODO(fmayer): Handle reconnect or similar.
+ // This is just to prevent a deadlock.
+ PERFETTO_CHECK(++dead_sockets_ != sockets_.size());
+ return;
+ }
std::unique_lock<std::mutex> lck_(mtx_);
PERFETTO_CHECK(available_sockets_ < sockets_.size());
sockets_[available_sockets_++] = std::move(sock);
diff --git a/src/profiling/memory/client.h b/src/profiling/memory/client.h
index a3aa5c6..7a4e459 100644
--- a/src/profiling/memory/client.h
+++ b/src/profiling/memory/client.h
@@ -18,6 +18,7 @@
#define SRC_PROFILING_MEMORY_CLIENT_H_
#include <stddef.h>
+
#include <mutex>
#include <vector>
@@ -27,6 +28,22 @@
class SocketPool;
+class FreePage {
+ public:
+ FreePage();
+
+ // Can be called from any thread. Must not hold mtx_.`
+ void Add(const uint64_t addr, SocketPool* pool);
+
+ private:
+ // Needs to be called holding mtx_.
+ void Flush(SocketPool* pool);
+
+ std::vector<uint64_t> free_page_;
+ std::mutex mtx_;
+ size_t offset_;
+};
+
class BorrowedSocket {
public:
BorrowedSocket(const BorrowedSocket&) = delete;
@@ -61,6 +78,7 @@
std::condition_variable cv_;
std::vector<base::ScopedFile> sockets_;
size_t available_sockets_;
+ size_t dead_sockets_ = 0;
};
} // namespace perfetto