aboutsummaryrefslogtreecommitdiff
path: root/src/profiling/ProfilingConnectionDumpToFileDecorator.cpp
blob: f00d7fa96589b239a25d746efb17cbd260283273 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//
// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include "ProfilingConnectionDumpToFileDecorator.hpp"

#include <armnn/Exceptions.hpp>
#include <armnn/utility/NumericCast.hpp>

#include <fstream>

namespace armnn
{

namespace profiling
{

ProfilingConnectionDumpToFileDecorator::ProfilingConnectionDumpToFileDecorator(
    std::unique_ptr<IProfilingConnection> connection,
    const ProfilingOptions& options,
    bool ignoreFailures)
      : m_Connection(std::move(connection))
      , m_Options(options)
      , m_IgnoreFileErrors(ignoreFailures)
{
    if (!m_Connection)
    {
        throw InvalidArgumentException("Connection cannot be nullptr");
    }
}

ProfilingConnectionDumpToFileDecorator::~ProfilingConnectionDumpToFileDecorator()
{
    Close();
}

bool ProfilingConnectionDumpToFileDecorator::IsOpen() const
{
    return m_Connection->IsOpen();
}

void ProfilingConnectionDumpToFileDecorator::Close()
{
    m_IncomingDumpFileStream.flush();
    m_IncomingDumpFileStream.close();
    m_OutgoingDumpFileStream.flush();
    m_OutgoingDumpFileStream.close();
    m_Connection->Close();
}

bool ProfilingConnectionDumpToFileDecorator::WritePacket(const unsigned char* buffer, uint32_t length)
{
    bool success = true;
    if (!m_Options.m_OutgoingCaptureFile.empty())
    {
        success &= DumpOutgoingToFile(buffer, length);
    }
    success &= m_Connection->WritePacket(buffer, length);
    return success;
}

arm::pipe::Packet ProfilingConnectionDumpToFileDecorator::ReadPacket(uint32_t timeout)
{
    arm::pipe::Packet packet = m_Connection->ReadPacket(timeout);
    if (!m_Options.m_IncomingCaptureFile.empty())
    {
        DumpIncomingToFile(packet);
    }
    return packet;
}

bool ProfilingConnectionDumpToFileDecorator::OpenIncomingDumpFile()
{
    m_IncomingDumpFileStream.open(m_Options.m_IncomingCaptureFile, std::ios::out | std::ios::binary);
    return m_IncomingDumpFileStream.is_open();
}

bool ProfilingConnectionDumpToFileDecorator::OpenOutgoingDumpFile()
{
    m_OutgoingDumpFileStream.open(m_Options.m_OutgoingCaptureFile, std::ios::out | std::ios::binary);
    return m_OutgoingDumpFileStream.is_open();
}


/// Dumps incoming data into the file specified by m_Settings.m_IncomingDumpFileName.
/// If m_IgnoreFileErrors is set to true in m_Settings, write errors will be ignored,
/// i.e. the method will not throw an exception if it encounters an error while trying
/// to write the data into the specified file.
/// @param packet data packet to write
/// @return nothing
void ProfilingConnectionDumpToFileDecorator::DumpIncomingToFile(const arm::pipe::Packet& packet)
{
    bool success = true;
    if (!m_IncomingDumpFileStream.is_open())
    {
        // attempt to open dump file
        success &= OpenIncomingDumpFile();
        if (!(success || m_IgnoreFileErrors))
        {
            Fail("Failed to open \"" + m_Options.m_IncomingCaptureFile + "\" for writing");
        }
    }

    // attempt to write binary data from packet
    const unsigned int header       = packet.GetHeader();
    const unsigned int packetLength = packet.GetLength();

    m_IncomingDumpFileStream.write(reinterpret_cast<const char*>(&header), sizeof header);
    m_IncomingDumpFileStream.write(reinterpret_cast<const char*>(&packetLength), sizeof packetLength);
    m_IncomingDumpFileStream.write(reinterpret_cast<const char*>(packet.GetData()),
                                   armnn::numeric_cast<std::streamsize>(packetLength));

    success &= m_IncomingDumpFileStream.good();
    if (!(success || m_IgnoreFileErrors))
    {
        Fail("Error writing incoming packet of " + std::to_string(packetLength) + " bytes");
    }
}

/// Dumps outgoing data into the file specified by m_Settings.m_OutgoingDumpFileName.
/// If m_IgnoreFileErrors is set to true in m_Settings, write errors will be ignored,
/// i.e. the method will not throw an exception if it encounters an error while trying
/// to write the data into the specified file. However, the return value will still
/// signal if the write has not been completed succesfully.
/// @param buffer pointer to data to write
/// @param length number of bytes to write
/// @return true if write successful, false otherwise
bool ProfilingConnectionDumpToFileDecorator::DumpOutgoingToFile(const unsigned char* buffer, uint32_t length)
{
    bool success = true;
    if (!m_OutgoingDumpFileStream.is_open())
    {
        // attempt to open dump file
        success &= OpenOutgoingDumpFile();
        if (!(success || m_IgnoreFileErrors))
        {
            Fail("Failed to open \"" + m_Options.m_OutgoingCaptureFile + "\" for writing");
        }
    }

    // attempt to write binary data
    m_OutgoingDumpFileStream.write(reinterpret_cast<const char*>(buffer),
                                   armnn::numeric_cast<std::streamsize>(length));
    success &= m_OutgoingDumpFileStream.good();
    if (!(success || m_IgnoreFileErrors))
    {
        Fail("Error writing outgoing packet of " + std::to_string(length) + " bytes");
    }

    return success;
}

void ProfilingConnectionDumpToFileDecorator::Fail(const std::string& errorMessage)
{
    Close();
    throw RuntimeException(errorMessage);
}

} // namespace profiling

} // namespace armnn