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