• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 #include "src/profiling/memory/wire_protocol.h"
18 #include "perfetto/base/logging.h"
19 #include "perfetto/base/scoped_file.h"
20 #include "perfetto/base/unix_socket.h"
21 
22 #include <sys/socket.h>
23 #include <sys/types.h>
24 
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 
28 namespace perfetto {
29 namespace profiling {
30 
31 bool operator==(const AllocMetadata& one, const AllocMetadata& other);
operator ==(const AllocMetadata & one,const AllocMetadata & other)32 bool operator==(const AllocMetadata& one, const AllocMetadata& other) {
33   return std::tie(one.sequence_number, one.alloc_size, one.alloc_address,
34                   one.stack_pointer, one.stack_pointer_offset, one.arch) ==
35              std::tie(other.sequence_number, other.alloc_size,
36                       other.alloc_address, other.stack_pointer,
37                       other.stack_pointer_offset, other.arch) &&
38          memcmp(one.register_data, other.register_data, kMaxRegisterDataSize) ==
39              0;
40 }
41 
42 bool operator==(const FreeBatch& one, const FreeBatch& other);
operator ==(const FreeBatch & one,const FreeBatch & other)43 bool operator==(const FreeBatch& one, const FreeBatch& other) {
44   if (one.num_entries != other.num_entries)
45     return false;
46   for (size_t i = 0; i < one.num_entries; ++i) {
47     if (std::tie(one.entries[i].sequence_number, one.entries[i].addr) !=
48         std::tie(other.entries[i].sequence_number, other.entries[i].addr))
49       return false;
50   }
51   return true;
52 }
53 
54 namespace {
55 
CopyFD(int fd)56 base::ScopedFile CopyFD(int fd) {
57   int sv[2];
58   PERFETTO_CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
59   base::UnixSocketRaw send_sock(base::ScopedFile(sv[0]),
60                                 base::SockType::kStream);
61   base::UnixSocketRaw recv_sock(base::ScopedFile(sv[1]),
62                                 base::SockType::kStream);
63   char msg[] = "a";
64   PERFETTO_CHECK(send_sock.Send(msg, sizeof(msg), &fd, 1));
65   base::ScopedFile res;
66   recv_sock.Receive(msg, sizeof(msg), &res, 1);
67   return res;
68 }
69 
70 constexpr auto kShmemSize = 1048576;
71 
TEST(WireProtocolTest,AllocMessage)72 TEST(WireProtocolTest, AllocMessage) {
73   char payload[] = {0x77, 0x77, 0x77, 0x00};
74   WireMessage msg = {};
75   msg.record_type = RecordType::Malloc;
76   AllocMetadata metadata = {};
77   metadata.sequence_number = 0xA1A2A3A4A5A6A7A8;
78   metadata.alloc_size = 0xB1B2B3B4B5B6B7B8;
79   metadata.alloc_address = 0xC1C2C3C4C5C6C7C8;
80   metadata.stack_pointer = 0xD1D2D3D4D5D6D7D8;
81   metadata.stack_pointer_offset = 0xE1E2E3E4E5E6E7E8;
82   metadata.arch = unwindstack::ARCH_X86;
83   for (size_t i = 0; i < kMaxRegisterDataSize; ++i)
84     metadata.register_data[i] = 0x66;
85   msg.alloc_header = &metadata;
86   msg.payload = payload;
87   msg.payload_size = sizeof(payload);
88 
89   auto shmem_client = SharedRingBuffer::Create(kShmemSize);
90   ASSERT_TRUE(shmem_client);
91   ASSERT_TRUE(shmem_client->is_valid());
92   auto shmem_server = SharedRingBuffer::Attach(CopyFD(shmem_client->fd()));
93 
94   ASSERT_TRUE(SendWireMessage(&shmem_client.value(), msg));
95 
96   auto buf = shmem_server->BeginRead();
97   ASSERT_TRUE(buf);
98   WireMessage recv_msg;
99   ASSERT_TRUE(ReceiveWireMessage(reinterpret_cast<char*>(buf.data), buf.size,
100                                  &recv_msg));
101   shmem_server->EndRead(std::move(buf));
102 
103   ASSERT_EQ(recv_msg.record_type, msg.record_type);
104   ASSERT_EQ(*recv_msg.alloc_header, *msg.alloc_header);
105   ASSERT_EQ(recv_msg.payload_size, msg.payload_size);
106   ASSERT_STREQ(recv_msg.payload, msg.payload);
107 }
108 
TEST(WireProtocolTest,FreeMessage)109 TEST(WireProtocolTest, FreeMessage) {
110   WireMessage msg = {};
111   msg.record_type = RecordType::Free;
112   FreeBatch batch = {};
113   batch.num_entries = kFreeBatchSize;
114   for (size_t i = 0; i < kFreeBatchSize; ++i) {
115     batch.entries[i].sequence_number = 0x111111111111111;
116     batch.entries[i].addr = 0x222222222222222;
117   }
118   msg.free_header = &batch;
119 
120   auto shmem_client = SharedRingBuffer::Create(kShmemSize);
121   ASSERT_TRUE(shmem_client);
122   ASSERT_TRUE(shmem_client->is_valid());
123   auto shmem_server = SharedRingBuffer::Attach(CopyFD(shmem_client->fd()));
124 
125   ASSERT_TRUE(SendWireMessage(&shmem_client.value(), msg));
126 
127   auto buf = shmem_server->BeginRead();
128   ASSERT_TRUE(buf);
129   WireMessage recv_msg;
130   ASSERT_TRUE(ReceiveWireMessage(reinterpret_cast<char*>(buf.data), buf.size,
131                                  &recv_msg));
132   shmem_server->EndRead(std::move(buf));
133 
134   ASSERT_EQ(recv_msg.record_type, msg.record_type);
135   ASSERT_EQ(*recv_msg.free_header, *msg.free_header);
136   ASSERT_EQ(recv_msg.payload_size, msg.payload_size);
137 }
138 
139 }  // namespace
140 }  // namespace profiling
141 }  // namespace perfetto
142