• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #define LOG_TAG "ArmnnDriver"
7 
8 #include "RequestThread.hpp"
9 #include "ArmnnPreparedModel.hpp"
10 
11 #ifdef ARMNN_ANDROID_NN_V1_2
12 #include "ArmnnPreparedModel_1_2.hpp"
13 #endif
14 
15 #ifdef ARMNN_ANDROID_NN_V1_3
16 #include "ArmnnPreparedModel_1_2.hpp"
17 #include "ArmnnPreparedModel_1_3.hpp"
18 #endif
19 
20 #include <armnn/utility/Assert.hpp>
21 
22 #include <log/log.h>
23 
24 using namespace android;
25 
26 namespace armnn_driver
27 {
28 
29 template <template <typename HalVersion> class PreparedModel, typename HalVersion, typename CallbackContext>
RequestThread()30 RequestThread<PreparedModel, HalVersion, CallbackContext>::RequestThread()
31 {
32     ALOGV("RequestThread::RequestThread()");
33     m_Thread = std::make_unique<std::thread>(&RequestThread::Process, this);
34 }
35 
36 template <template <typename HalVersion> class PreparedModel, typename HalVersion, typename CallbackContext>
~RequestThread()37 RequestThread<PreparedModel, HalVersion, CallbackContext>::~RequestThread()
38 {
39     ALOGV("RequestThread::~RequestThread()");
40 
41     try
42     {
43         // Coverity fix: The following code may throw an exception of type std::length_error.
44 
45         // This code is meant to to terminate the inner thread gracefully by posting an EXIT message
46         // to the thread's message queue. However, according to Coverity, this code could throw an exception and fail.
47         // Since only one static instance of RequestThread is used in the driver (in ArmnnPreparedModel),
48         // this destructor is called only when the application has been closed, which means that
49         // the inner thread will be terminated anyway, although abruptly, in the event that the destructor code throws.
50         // Wrapping the destructor's code with a try-catch block simply fixes the Coverity bug.
51 
52         // Post an EXIT message to the thread
53         std::shared_ptr<AsyncExecuteData> nulldata(nullptr);
54         auto pMsg = std::make_shared<ThreadMsg>(ThreadMsgType::EXIT, nulldata);
55         PostMsg(pMsg);
56         // Wait for the thread to terminate, it is deleted automatically
57         m_Thread->join();
58     }
59     catch (const std::exception&) { } // Swallow any exception.
60 }
61 
62 template <template <typename HalVersion> class PreparedModel, typename HalVersion, typename CallbackContext>
PostMsg(PreparedModel<HalVersion> * model,std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>> & memPools,std::shared_ptr<armnn::InputTensors> & inputTensors,std::shared_ptr<armnn::OutputTensors> & outputTensors,CallbackContext callbackContext)63 void RequestThread<PreparedModel, HalVersion, CallbackContext>::PostMsg(PreparedModel<HalVersion>* model,
64         std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& memPools,
65         std::shared_ptr<armnn::InputTensors>& inputTensors,
66         std::shared_ptr<armnn::OutputTensors>& outputTensors,
67         CallbackContext callbackContext)
68 {
69     ALOGV("RequestThread::PostMsg(...)");
70     auto data = std::make_shared<AsyncExecuteData>(model,
71                                                    memPools,
72                                                    inputTensors,
73                                                    outputTensors,
74                                                    callbackContext);
75     auto pMsg = std::make_shared<ThreadMsg>(ThreadMsgType::REQUEST, data);
76     PostMsg(pMsg);
77 }
78 
79 template <template <typename HalVersion> class PreparedModel, typename HalVersion, typename CallbackContext>
PostMsg(std::shared_ptr<ThreadMsg> & pMsg)80 void RequestThread<PreparedModel, HalVersion, CallbackContext>::PostMsg(std::shared_ptr<ThreadMsg>& pMsg)
81 {
82     ALOGV("RequestThread::PostMsg(pMsg)");
83     // Add a message to the queue and notify the request thread
84     std::unique_lock<std::mutex> lock(m_Mutex);
85     m_Queue.push(pMsg);
86     m_Cv.notify_one();
87 }
88 
89 template <template <typename HalVersion> class PreparedModel, typename HalVersion, typename CallbackContext>
Process()90 void RequestThread<PreparedModel, HalVersion, CallbackContext>::Process()
91 {
92     ALOGV("RequestThread::Process()");
93     while (true)
94     {
95         std::shared_ptr<ThreadMsg> pMsg(nullptr);
96         {
97             // Wait for a message to be added to the queue
98             // This is in a separate scope to minimise the lifetime of the lock
99             std::unique_lock<std::mutex> lock(m_Mutex);
100             while (m_Queue.empty())
101             {
102                 m_Cv.wait(lock);
103             }
104             // get the message to process from the front of the queue
105             pMsg = m_Queue.front();
106             m_Queue.pop();
107         }
108 
109         switch (pMsg->type)
110         {
111             case ThreadMsgType::REQUEST:
112             {
113                 ALOGV("RequestThread::Process() - request");
114                 // invoke the asynchronous execution method
115                 PreparedModel<HalVersion>* model = pMsg->data->m_Model;
116                 model->ExecuteGraph(pMsg->data->m_MemPools,
117                                     *(pMsg->data->m_InputTensors),
118                                     *(pMsg->data->m_OutputTensors),
119                                     pMsg->data->m_CallbackContext);
120                 break;
121             }
122 
123             case ThreadMsgType::EXIT:
124             {
125                 ALOGV("RequestThread::Process() - exit");
126                 // delete all remaining messages (there should not be any)
127                 std::unique_lock<std::mutex> lock(m_Mutex);
128                 while (!m_Queue.empty())
129                 {
130                     m_Queue.pop();
131                 }
132                 return;
133             }
134 
135             default:
136                 // this should be unreachable
137                 ALOGE("RequestThread::Process() - invalid message type");
138                 ARMNN_ASSERT_MSG(false, "ArmNN: RequestThread: invalid message type");
139         }
140     }
141 }
142 
143 ///
144 /// Class template specializations
145 ///
146 
147 template class RequestThread<ArmnnPreparedModel, hal_1_0::HalPolicy, CallbackContext_1_0>;
148 
149 #ifdef ARMNN_ANDROID_NN_V1_1
150 template class RequestThread<armnn_driver::ArmnnPreparedModel, hal_1_1::HalPolicy, CallbackContext_1_0>;
151 #endif
152 
153 #ifdef ARMNN_ANDROID_NN_V1_2
154 template class RequestThread<ArmnnPreparedModel, hal_1_1::HalPolicy, CallbackContext_1_0>;
155 template class RequestThread<ArmnnPreparedModel, hal_1_2::HalPolicy, CallbackContext_1_0>;
156 template class RequestThread<ArmnnPreparedModel_1_2, hal_1_2::HalPolicy, CallbackContext_1_2>;
157 #endif
158 
159 #ifdef ARMNN_ANDROID_NN_V1_3
160 template class RequestThread<ArmnnPreparedModel, hal_1_1::HalPolicy, CallbackContext_1_0>;
161 template class RequestThread<ArmnnPreparedModel, hal_1_2::HalPolicy, CallbackContext_1_0>;
162 template class RequestThread<ArmnnPreparedModel, hal_1_3::HalPolicy, CallbackContext_1_0>;
163 template class RequestThread<ArmnnPreparedModel_1_2, hal_1_2::HalPolicy, CallbackContext_1_2>;
164 #endif
165 
166 } // namespace armnn_driver
167