Remove input, output buffers from process kernel
[tidl/tidl-api.git] / examples / test / multiple_executors.cpp
1 /******************************************************************************
2  * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/
3  *   All rights reserved.
4  *
5  *   Redistribution and use in source and binary forms, with or without
6  *   modification, are permitted provided that the following conditions are met:
7  *       * Redistributions of source code must retain the above copyright
8  *         notice, this list of conditions and the following disclaimer.
9  *       * Redistributions in binary form must reproduce the above copyright
10  *         notice, this list of conditions and the following disclaimer in the
11  *         documentation and/or other materials provided with the distribution.
12  *       * Neither the name of Texas Instruments Incorporated nor the
13  *         names of its contributors may be used to endorse or promote products
14  *         derived from this software without specific prior written permission.
15  *
16  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  *   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  *   THE POSSIBILITY OF SUCH DAMAGE.
27  *****************************************************************************/
29 //! @file multiple_executors.cpp
30 //! Illustrates how to setup multiple Executor instances using
31 //! non-overlapping sets of device ids and running the Executor instances
32 //! in parallel - each in its own thread
34 #include <signal.h>
35 #include <getopt.h>
36 #include <iostream>
37 #include <fstream>
38 #include <cassert>
39 #include <string>
40 #include <functional>
41 #include <algorithm>
42 #include <pthread.h>
44 #include "executor.h"
45 #include "execution_object.h"
46 #include "configuration.h"
48 using namespace tidl;
50 extern bool ReadFrame(ExecutionObject&     eo,
51                int                  frame_idx,
52                const Configuration& configuration,
53                std::istream&        input_file);
55 extern bool WriteFrame(const ExecutionObject &eo,
56                 std::ostream& output_file);
58 void* run_network(void *data);
60 struct ThreadArg
61 {
62     std::string config_file;
63     DeviceIds ids;
64     ThreadArg(const DeviceIds& ids, const std::string& s):
65         ids(ids), config_file(s) {}
67 };
69 bool thread_status[2];
71 bool RunMultipleExecutors(const std::string& config_file_1,
72                           const std::string& config_file_2,
73                           uint32_t num_devices_available)
74 {
75     // If there is only 1 device available, skip
76     if (num_devices_available == 1)
77         return true;
79     DeviceIds ids1, ids2;
81     if (num_devices_available == 4)
82     {
83         ids1 = {DeviceId::ID2, DeviceId::ID3};
84         ids2 = {DeviceId::ID0, DeviceId::ID1};
85     }
86     else
87     {
88         ids1 = {DeviceId::ID0};
89         ids2 = {DeviceId::ID1};
90     }
92     // Set up devices and config files for each thread
93     ThreadArg arg1(ids2, config_file_1);
94     ThreadArg arg2(ids1, config_file_2);
96     // Run network 1 in a thread
97     std::cout << std::endl << "Multiple Executor..." << std::endl;
98     std::cout << "Running network "
99               << arg1.config_file.substr(arg1.config_file.find("tidl"))
100               << " on EVEs: ";
101     for (DeviceId id : arg1.ids)
102         std::cout << static_cast<int>(id) << " ";
103     std::cout << " in thread 0" << std::endl;
105     pthread_t network_thread_1;
106     pthread_create(&network_thread_1, 0, &run_network, &arg1);
108     // Run network 2 in a thread
109     std::cout << "Running network "
110               << arg2.config_file.substr(arg2.config_file.find("tidl"))
111               << " on EVEs: ";
112     for (DeviceId id : arg2.ids)
113         std::cout << static_cast<int>(id) << " ";
114     std::cout << " in thread 1" << std::endl;
116     pthread_t network_thread_2;
117     pthread_create(&network_thread_2, 0, &run_network, &arg2);
119     // Wait for both networks to complete
120     void *thread_return_val1;
121     void *thread_return_val2;
122     pthread_join(network_thread_1, &thread_return_val1);
123     pthread_join(network_thread_2, &thread_return_val2);
125     if (thread_return_val1 == 0 || thread_return_val2 == 0)
126     {
127         std::cout << "Multiple executors: FAILED" << std::endl;
128         return false;
129     }
131     std::cout << "Multiple executors: PASSED" << std::endl;
132     return true;
136 void* run_network(void *data)
138     const ThreadArg* arg = static_cast<const ThreadArg *>(data);
140     const DeviceIds& ids = arg->ids;
141     const std::string& config_file = arg->config_file;
143     // Read the TI DL configuration file
144     Configuration configuration;
145     bool status = configuration.ReadFromFile(config_file);
146     assert (status != false);
148     configuration.outData += std::to_string(pthread_self());
150     // Open input and output files
151     std::ifstream input_data_file(configuration.inData, std::ios::binary);
152     std::ofstream output_data_file(configuration.outData, std::ios::binary);
153     assert (input_data_file.good());
154     assert (output_data_file.good());
156     // Determine input frame size from configuration
157     size_t frame_sz = configuration.inWidth * configuration.inHeight *
158                       configuration.inNumChannels;
160     try
161     {
162         // Create a executor with the approriate core type, number of cores
163         // and configuration specified
164         Executor executor(DeviceType::EVE, ids, configuration);
166         const ExecutionObjects& execution_objects =
167                                                 executor.GetExecutionObjects();
168         int num_eos = execution_objects.size();
170         // Allocate input and output buffers for each execution object
171         std::vector<void *> buffers;
172         for (auto &eo : execution_objects)
173         {
174             ArgInfo in  = { ArgInfo(malloc_ddr<char>(frame_sz), frame_sz)};
175             ArgInfo out = { ArgInfo(malloc_ddr<char>(frame_sz), frame_sz)};
176             eo->SetInputOutputBuffer(in, out);
178             buffers.push_back(in.ptr());
179             buffers.push_back(out.ptr());
180         }
182         // Process frames with available execution objects in a pipelined manner
183         // additional num_eos iterations to flush the pipeline (epilogue)
184         for (int frame_idx = 0;
185              frame_idx < configuration.numFrames + num_eos; frame_idx++)
186         {
187             ExecutionObject* eo = execution_objects[frame_idx % num_eos].get();
189             // Wait for previous frame on the same eo to finish processing
190             if (eo->ProcessFrameWait())
191                 WriteFrame(*eo, output_data_file);
193             // Read a frame and start processing it with current eo
194             if (ReadFrame(*eo, frame_idx, configuration, input_data_file))
195                 eo->ProcessFrameStartAsync();
196         }
199         for (auto b : buffers)
200             __free_ddr(b);
201     }
202     catch (tidl::Exception &e)
203     {
204         std::cerr << e.what() << std::endl;
205         status = false;
206     }
208     input_data_file.close();
209     output_data_file.close();
211     // Return 1 for true, 0 for false. void * pattern follows example from:
212     // "Advanced programming in the Unix Environment"
213     if (!status) return ((void *)0);
215     return ((void *)1);