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