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