84aae9d39fb5c7396bd28afc690a73bc9f81247b
[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 #include <armnn/utility/NumericCast.hpp>
10
11 #include <fstream>
12
13 namespace armnn
14 {
15
16 namespace profiling
17 {
18
19 ProfilingConnectionDumpToFileDecorator::ProfilingConnectionDumpToFileDecorator(
20     std::unique_ptr<IProfilingConnection> connection,
21     const Runtime::CreationOptions::ExternalProfilingOptions& 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 InvalidArgumentException("Connection cannot be nullptr");
30     }
31 }
32
33 ProfilingConnectionDumpToFileDecorator::~ProfilingConnectionDumpToFileDecorator()
34 {
35     Close();
36 }
37
38 bool ProfilingConnectionDumpToFileDecorator::IsOpen() const
39 {
40     return m_Connection->IsOpen();
41 }
42
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
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
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
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
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
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                                    armnn::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
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                                    armnn::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
154 void ProfilingConnectionDumpToFileDecorator::Fail(const std::string& errorMessage)
155 {
156     Close();
157     throw RuntimeException(errorMessage);
158 }
159
160 } // namespace profiling
161
162 } // namespace armnn