blob: 4bbbc2962c92c688d47ff4cb903d3c7bc5796efe [file] [log] [blame]
Teresa Charlin9bab4962019-09-06 12:28:35 +01001//
2// Copyright © 2019 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "SocketProfilingConnection.hpp"
7
Colm Donelana21620d2019-10-11 13:09:49 +01008#include <cerrno>
Teresa Charlin9bab4962019-09-06 12:28:35 +01009#include <fcntl.h>
Teresa Charlin9bab4962019-09-06 12:28:35 +010010#include <string>
11
Rob Hughes25b74362020-01-13 11:14:59 +000012using namespace armnnUtils;
13
Teresa Charlin9bab4962019-09-06 12:28:35 +010014namespace armnn
15{
16namespace profiling
17{
18
19SocketProfilingConnection::SocketProfilingConnection()
20{
Rob Hughes25b74362020-01-13 11:14:59 +000021 Sockets::Initialize();
Teresa Charlin9bab4962019-09-06 12:28:35 +010022 memset(m_Socket, 0, sizeof(m_Socket));
23 // Note: we're using Linux specific SOCK_CLOEXEC flag.
24 m_Socket[0].fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
25 if (m_Socket[0].fd == -1)
26 {
Colm Donelana21620d2019-10-11 13:09:49 +010027 throw armnn::RuntimeException(std::string("Socket construction failed: ") + strerror(errno));
Teresa Charlin9bab4962019-09-06 12:28:35 +010028 }
29
30 // Connect to the named unix domain socket.
Rob Hughes25b74362020-01-13 11:14:59 +000031 sockaddr_un server{};
Teresa Charlin9bab4962019-09-06 12:28:35 +010032 memset(&server, 0, sizeof(sockaddr_un));
33 // As m_GatorNamespace begins with a null character we need to ignore that when getting its length.
34 memcpy(server.sun_path, m_GatorNamespace, strlen(m_GatorNamespace + 1) + 1);
35 server.sun_family = AF_UNIX;
36 if (0 != connect(m_Socket[0].fd, reinterpret_cast<const sockaddr*>(&server), sizeof(sockaddr_un)))
37 {
Colm Donelan9ea77002019-10-17 14:02:44 +010038 Close();
Colm Donelana21620d2019-10-11 13:09:49 +010039 throw armnn::RuntimeException(std::string("Cannot connect to stream socket: ") + strerror(errno));
Teresa Charlin9bab4962019-09-06 12:28:35 +010040 }
41
42 // Our socket will only be interested in polling reads.
43 m_Socket[0].events = POLLIN;
44
45 // Make the socket non blocking.
Rob Hughes25b74362020-01-13 11:14:59 +000046 if (!Sockets::SetNonBlocking(m_Socket[0].fd))
Teresa Charlin9bab4962019-09-06 12:28:35 +010047 {
Colm Donelan9ea77002019-10-17 14:02:44 +010048 Close();
Colm Donelana21620d2019-10-11 13:09:49 +010049 throw armnn::RuntimeException(std::string("Failed to set socket as non blocking: ") + strerror(errno));
Teresa Charlin9bab4962019-09-06 12:28:35 +010050 }
51}
52
Matteo Martincigh54fb9572019-10-02 12:50:57 +010053bool SocketProfilingConnection::IsOpen() const
Teresa Charlin9bab4962019-09-06 12:28:35 +010054{
Matteo Martincigh24e8f922019-09-19 11:57:46 +010055 return m_Socket[0].fd > 0;
Teresa Charlin9bab4962019-09-06 12:28:35 +010056}
57
58void SocketProfilingConnection::Close()
59{
Rob Hughes25b74362020-01-13 11:14:59 +000060 if (Sockets::Close(m_Socket[0].fd) != 0)
FinnWilliamsArma0c78712019-09-16 12:06:47 +010061 {
Colm Donelana21620d2019-10-11 13:09:49 +010062 throw armnn::RuntimeException(std::string("Cannot close stream socket: ") + strerror(errno));
FinnWilliamsArma0c78712019-09-16 12:06:47 +010063 }
Matteo Martincigh24e8f922019-09-19 11:57:46 +010064
65 memset(m_Socket, 0, sizeof(m_Socket));
Teresa Charlin9bab4962019-09-06 12:28:35 +010066}
67
Matteo Martincigh24e8f922019-09-19 11:57:46 +010068bool SocketProfilingConnection::WritePacket(const unsigned char* buffer, uint32_t length)
Teresa Charlin9bab4962019-09-06 12:28:35 +010069{
Matteo Martincigh24e8f922019-09-19 11:57:46 +010070 if (buffer == nullptr || length == 0)
FinnWilliamsArma0c78712019-09-16 12:06:47 +010071 {
72 return false;
73 }
Matteo Martincigh24e8f922019-09-19 11:57:46 +010074
Rob Hughes25b74362020-01-13 11:14:59 +000075 return Sockets::Write(m_Socket[0].fd, buffer, length) != -1;
Teresa Charlin9bab4962019-09-06 12:28:35 +010076}
77
78Packet SocketProfilingConnection::ReadPacket(uint32_t timeout)
79{
Matteo Martincigh8d9590e2019-10-15 09:35:29 +010080 // Is there currently at least a header worth of data waiting to be read?
81 int bytes_available = 0;
Rob Hughes25b74362020-01-13 11:14:59 +000082 Sockets::Ioctl(m_Socket[0].fd, FIONREAD, &bytes_available);
Colm Donelana21620d2019-10-11 13:09:49 +010083 if (bytes_available >= 8)
FinnWilliamsArma0c78712019-09-16 12:06:47 +010084 {
Colm Donelana21620d2019-10-11 13:09:49 +010085 // Yes there is. Read it:
86 return ReceivePacket();
87 }
Matteo Martincigh8d9590e2019-10-15 09:35:29 +010088
89 // Poll for data on the socket or until timeout occurs
Rob Hughes25b74362020-01-13 11:14:59 +000090 int pollResult = Sockets::Poll(&m_Socket[0], 1, static_cast<int>(timeout));
Matteo Martincigh8d9590e2019-10-15 09:35:29 +010091
92 switch (pollResult)
Colm Donelana21620d2019-10-11 13:09:49 +010093 {
Matteo Martincigh8d9590e2019-10-15 09:35:29 +010094 case -1: // Error
95 throw armnn::RuntimeException(std::string("Read failure from socket: ") + strerror(errno));
Matteo Martincigh24e8f922019-09-19 11:57:46 +010096
Matteo Martincigh8d9590e2019-10-15 09:35:29 +010097 case 0: // Timeout
98 throw TimeoutException("Timeout while reading from socket");
99
100 default: // Normal poll return but it could still contain an error signal
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100101 // Check if the socket reported an error
102 if (m_Socket[0].revents & (POLLNVAL | POLLERR | POLLHUP))
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100103 {
Colm Donelan9ea77002019-10-17 14:02:44 +0100104 if (m_Socket[0].revents == POLLNVAL)
105 {
106 // This is an unrecoverable error.
107 Close();
108 throw armnn::RuntimeException(std::string("Error while polling receiving socket: POLLNVAL"));
109 }
110 if (m_Socket[0].revents == POLLERR)
111 {
112 throw armnn::RuntimeException(std::string("Error while polling receiving socket: POLLERR: ") +
113 strerror(errno));
114 }
115 if (m_Socket[0].revents == POLLHUP)
116 {
117 // This is an unrecoverable error.
118 Close();
119 throw armnn::RuntimeException(std::string("Connection closed by remote client: POLLHUP"));
120 }
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100121 }
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100122
123 // Check if there is data to read
124 if (!(m_Socket[0].revents & (POLLIN)))
125 {
Colm Donelan9ea77002019-10-17 14:02:44 +0100126 // This is a corner case. The socket as been woken up but not with any data.
127 // We'll throw a timeout exception to loop around again.
128 throw armnn::TimeoutException("File descriptor was polled but no data was available to receive.");
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100129 }
130
131 return ReceivePacket();
Colm Donelana21620d2019-10-11 13:09:49 +0100132 }
133}
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100134
Colm Donelana21620d2019-10-11 13:09:49 +0100135Packet SocketProfilingConnection::ReceivePacket()
136{
137 char header[8] = {};
Rob Hughes25b74362020-01-13 11:14:59 +0000138 long receiveResult = Sockets::Read(m_Socket[0].fd, &header, sizeof(header));
Colm Donelan9ea77002019-10-17 14:02:44 +0100139 // We expect 8 as the result here. 0 means EOF, socket is closed. -1 means there been some other kind of error.
140 switch( receiveResult )
Colm Donelana21620d2019-10-11 13:09:49 +0100141 {
Colm Donelan9ea77002019-10-17 14:02:44 +0100142 case 0:
143 // Socket has closed.
144 Close();
145 throw armnn::RuntimeException("Remote socket has closed the connection.");
146 case -1:
147 // There's been a socket error. We will presume it's unrecoverable.
148 Close();
149 throw armnn::RuntimeException(std::string("Error occured on recv: ") + strerror(errno));
150 default:
151 if (receiveResult < 8)
152 {
153 throw armnn::RuntimeException("The received packet did not contains a valid MIPE header");
154 }
155 break;
Colm Donelana21620d2019-10-11 13:09:49 +0100156 }
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100157
Colm Donelana21620d2019-10-11 13:09:49 +0100158 // stream_metadata_identifier is the first 4 bytes
159 uint32_t metadataIdentifier = 0;
160 std::memcpy(&metadataIdentifier, header, sizeof(metadataIdentifier));
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100161
Colm Donelana21620d2019-10-11 13:09:49 +0100162 // data_length is the next 4 bytes
163 uint32_t dataLength = 0;
164 std::memcpy(&dataLength, header + 4u, sizeof(dataLength));
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100165
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100166 std::unique_ptr<unsigned char[]> packetData;
Colm Donelana21620d2019-10-11 13:09:49 +0100167 if (dataLength > 0)
168 {
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100169 packetData = std::make_unique<unsigned char[]>(dataLength);
Rob Hughes25b74362020-01-13 11:14:59 +0000170 long receivedLength = Sockets::Read(m_Socket[0].fd, packetData.get(), dataLength);
Jim Flynne11ff892019-10-04 04:25:43 -0700171 if (receivedLength < 0)
172 {
Rob Hughes25b74362020-01-13 11:14:59 +0000173 throw armnn::RuntimeException(std::string("Error occurred on recv: ") + strerror(errno));
Jim Flynne11ff892019-10-04 04:25:43 -0700174 }
175 if (dataLength != static_cast<uint32_t>(receivedLength))
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100176 {
177 // What do we do here if we can't read in a full packet?
Colm Donelana21620d2019-10-11 13:09:49 +0100178 throw armnn::RuntimeException("Invalid MIPE packet");
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100179 }
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100180 }
Colm Donelana21620d2019-10-11 13:09:49 +0100181
182 return Packet(metadataIdentifier, dataLength, packetData);
Teresa Charlin9bab4962019-09-06 12:28:35 +0100183}
184
185} // namespace profiling
186} // namespace armnn