1 //
2 // Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include "ProfilingConnectionDumpToFileDecorator.hpp"
7
8 #include <common/include/NumericCast.hpp>
9 #include <common/include/ProfilingException.hpp>
10
11 #include <fstream>
12
13 namespace arm
14 {
15
16 namespace pipe
17 {
18
ProfilingConnectionDumpToFileDecorator(std::unique_ptr<IProfilingConnection> connection,const ProfilingOptions & options,bool ignoreFailures)19 ProfilingConnectionDumpToFileDecorator::ProfilingConnectionDumpToFileDecorator(
20 std::unique_ptr<IProfilingConnection> connection,
21 const ProfilingOptions& options,
22 bool ignoreFailures)
23 : m_Connection(std::move(connection))
24 , m_Options(options)
25 , m_IgnoreFileErrors(ignoreFailures)
26 {
27 if (!m_Connection)
28 {
29 throw arm::pipe::InvalidArgumentException("Connection cannot be nullptr");
30 }
31 }
32
~ProfilingConnectionDumpToFileDecorator()33 ProfilingConnectionDumpToFileDecorator::~ProfilingConnectionDumpToFileDecorator()
34 {
35 Close();
36 }
37
IsOpen() const38 bool ProfilingConnectionDumpToFileDecorator::IsOpen() const
39 {
40 return m_Connection->IsOpen();
41 }
42
Close()43 void ProfilingConnectionDumpToFileDecorator::Close()
44 {
45 m_IncomingDumpFileStream.flush();
46 m_IncomingDumpFileStream.close();
47 m_OutgoingDumpFileStream.flush();
48 m_OutgoingDumpFileStream.close();
49 m_Connection->Close();
50 }
51
WritePacket(const unsigned char * buffer,uint32_t length)52 bool ProfilingConnectionDumpToFileDecorator::WritePacket(const unsigned char* buffer, uint32_t length)
53 {
54 bool success = true;
55 if (!m_Options.m_OutgoingCaptureFile.empty())
56 {
57 success &= DumpOutgoingToFile(buffer, length);
58 }
59 success &= m_Connection->WritePacket(buffer, length);
60 return success;
61 }
62
ReadPacket(uint32_t timeout)63 arm::pipe::Packet ProfilingConnectionDumpToFileDecorator::ReadPacket(uint32_t timeout)
64 {
65 arm::pipe::Packet packet = m_Connection->ReadPacket(timeout);
66 if (!m_Options.m_IncomingCaptureFile.empty())
67 {
68 DumpIncomingToFile(packet);
69 }
70 return packet;
71 }
72
OpenIncomingDumpFile()73 bool ProfilingConnectionDumpToFileDecorator::OpenIncomingDumpFile()
74 {
75 m_IncomingDumpFileStream.open(m_Options.m_IncomingCaptureFile, std::ios::out | std::ios::binary);
76 return m_IncomingDumpFileStream.is_open();
77 }
78
OpenOutgoingDumpFile()79 bool ProfilingConnectionDumpToFileDecorator::OpenOutgoingDumpFile()
80 {
81 m_OutgoingDumpFileStream.open(m_Options.m_OutgoingCaptureFile, std::ios::out | std::ios::binary);
82 return m_OutgoingDumpFileStream.is_open();
83 }
84
85
86 /// Dumps incoming data into the file specified by m_Settings.m_IncomingDumpFileName.
87 /// If m_IgnoreFileErrors is set to true in m_Settings, write errors will be ignored,
88 /// i.e. the method will not throw an exception if it encounters an error while trying
89 /// to write the data into the specified file.
90 /// @param packet data packet to write
91 /// @return nothing
DumpIncomingToFile(const arm::pipe::Packet & packet)92 void ProfilingConnectionDumpToFileDecorator::DumpIncomingToFile(const arm::pipe::Packet& packet)
93 {
94 bool success = true;
95 if (!m_IncomingDumpFileStream.is_open())
96 {
97 // attempt to open dump file
98 success &= OpenIncomingDumpFile();
99 if (!(success || m_IgnoreFileErrors))
100 {
101 Fail("Failed to open \"" + m_Options.m_IncomingCaptureFile + "\" for writing");
102 }
103 }
104
105 // attempt to write binary data from packet
106 const unsigned int header = packet.GetHeader();
107 const unsigned int packetLength = packet.GetLength();
108
109 m_IncomingDumpFileStream.write(reinterpret_cast<const char*>(&header), sizeof header);
110 m_IncomingDumpFileStream.write(reinterpret_cast<const char*>(&packetLength), sizeof packetLength);
111 m_IncomingDumpFileStream.write(reinterpret_cast<const char*>(packet.GetData()),
112 arm::pipe::numeric_cast<std::streamsize>(packetLength));
113
114 success &= m_IncomingDumpFileStream.good();
115 if (!(success || m_IgnoreFileErrors))
116 {
117 Fail("Error writing incoming packet of " + std::to_string(packetLength) + " bytes");
118 }
119 }
120
121 /// Dumps outgoing data into the file specified by m_Settings.m_OutgoingDumpFileName.
122 /// If m_IgnoreFileErrors is set to true in m_Settings, write errors will be ignored,
123 /// i.e. the method will not throw an exception if it encounters an error while trying
124 /// to write the data into the specified file. However, the return value will still
125 /// signal if the write has not been completed succesfully.
126 /// @param buffer pointer to data to write
127 /// @param length number of bytes to write
128 /// @return true if write successful, false otherwise
DumpOutgoingToFile(const unsigned char * buffer,uint32_t length)129 bool ProfilingConnectionDumpToFileDecorator::DumpOutgoingToFile(const unsigned char* buffer, uint32_t length)
130 {
131 bool success = true;
132 if (!m_OutgoingDumpFileStream.is_open())
133 {
134 // attempt to open dump file
135 success &= OpenOutgoingDumpFile();
136 if (!(success || m_IgnoreFileErrors))
137 {
138 Fail("Failed to open \"" + m_Options.m_OutgoingCaptureFile + "\" for writing");
139 }
140 }
141
142 // attempt to write binary data
143 m_OutgoingDumpFileStream.write(reinterpret_cast<const char*>(buffer),
144 arm::pipe::numeric_cast<std::streamsize>(length));
145 success &= m_OutgoingDumpFileStream.good();
146 if (!(success || m_IgnoreFileErrors))
147 {
148 Fail("Error writing outgoing packet of " + std::to_string(length) + " bytes");
149 }
150
151 return success;
152 }
153
Fail(const std::string & errorMessage)154 void ProfilingConnectionDumpToFileDecorator::Fail(const std::string& errorMessage)
155 {
156 Close();
157 throw arm::pipe::ProfilingException(errorMessage);
158 }
159
160 } // namespace pipe
161
162 } // namespace arm
163