xref: /aosp_15_r20/frameworks/native/cmds/dumpstate/DumpPool.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #ifndef FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
18*38e8c45fSAndroid Build Coastguard Worker #define FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
19*38e8c45fSAndroid Build Coastguard Worker 
20*38e8c45fSAndroid Build Coastguard Worker #include <future>
21*38e8c45fSAndroid Build Coastguard Worker #include <queue>
22*38e8c45fSAndroid Build Coastguard Worker #include <string>
23*38e8c45fSAndroid Build Coastguard Worker 
24*38e8c45fSAndroid Build Coastguard Worker #include <android-base/file.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <android-base/macros.h>
26*38e8c45fSAndroid Build Coastguard Worker 
27*38e8c45fSAndroid Build Coastguard Worker namespace android {
28*38e8c45fSAndroid Build Coastguard Worker namespace os {
29*38e8c45fSAndroid Build Coastguard Worker namespace dumpstate {
30*38e8c45fSAndroid Build Coastguard Worker 
31*38e8c45fSAndroid Build Coastguard Worker class DumpPoolTest;
32*38e8c45fSAndroid Build Coastguard Worker 
33*38e8c45fSAndroid Build Coastguard Worker /*
34*38e8c45fSAndroid Build Coastguard Worker  * Waits until the task is finished. Dumps the task results to the specified
35*38e8c45fSAndroid Build Coastguard Worker  * out_fd.
36*38e8c45fSAndroid Build Coastguard Worker  *
37*38e8c45fSAndroid Build Coastguard Worker  * |future| The task future.
38*38e8c45fSAndroid Build Coastguard Worker  * |title| Dump title string to the out_fd, an empty string for nothing.
39*38e8c45fSAndroid Build Coastguard Worker  * |out_fd| The target file to dump the result from the task.
40*38e8c45fSAndroid Build Coastguard Worker  */
41*38e8c45fSAndroid Build Coastguard Worker void WaitForTask(std::future<std::string> future, const std::string& title, int out_fd);
42*38e8c45fSAndroid Build Coastguard Worker 
43*38e8c45fSAndroid Build Coastguard Worker /*
44*38e8c45fSAndroid Build Coastguard Worker  * Waits until the task is finished. Dumps the task results to the STDOUT_FILENO.
45*38e8c45fSAndroid Build Coastguard Worker  */
46*38e8c45fSAndroid Build Coastguard Worker 
WaitForTask(std::future<std::string> future)47*38e8c45fSAndroid Build Coastguard Worker inline void WaitForTask(std::future<std::string> future) {
48*38e8c45fSAndroid Build Coastguard Worker     WaitForTask(std::move(future), "", STDOUT_FILENO);
49*38e8c45fSAndroid Build Coastguard Worker }
50*38e8c45fSAndroid Build Coastguard Worker 
51*38e8c45fSAndroid Build Coastguard Worker /*
52*38e8c45fSAndroid Build Coastguard Worker  * A thread pool with the fixed number of threads to execute multiple dump tasks
53*38e8c45fSAndroid Build Coastguard Worker  * simultaneously for dumpstate. The dump task is a callable function. It
54*38e8c45fSAndroid Build Coastguard Worker  * could include a file descriptor as a parameter to redirect dump results, if
55*38e8c45fSAndroid Build Coastguard Worker  * it needs to output results to the bugreport. This can avoid messing up
56*38e8c45fSAndroid Build Coastguard Worker  * bugreport's results when multiple dump tasks are running at the same time.
57*38e8c45fSAndroid Build Coastguard Worker  * Takes an example below for the usage of the DumpPool:
58*38e8c45fSAndroid Build Coastguard Worker  *
59*38e8c45fSAndroid Build Coastguard Worker  * void DumpFoo(int out_fd) {
60*38e8c45fSAndroid Build Coastguard Worker  *     dprintf(out_fd, "Dump result to out_fd ...");
61*38e8c45fSAndroid Build Coastguard Worker  * }
62*38e8c45fSAndroid Build Coastguard Worker  * ...
63*38e8c45fSAndroid Build Coastguard Worker  * DumpPool pool(tmp_root);
64*38e8c45fSAndroid Build Coastguard Worker  * auto task = pool.enqueueTaskWithFd("TaskName", &DumpFoo, std::placeholders::_1);
65*38e8c45fSAndroid Build Coastguard Worker  * ...
66*38e8c45fSAndroid Build Coastguard Worker  * WaitForTask(task);
67*38e8c45fSAndroid Build Coastguard Worker  *
68*38e8c45fSAndroid Build Coastguard Worker  * DumpFoo is a callable function included a out_fd parameter. Using the
69*38e8c45fSAndroid Build Coastguard Worker  * enqueueTaskWithFd method in DumpPool to enqueue the task to the pool. The
70*38e8c45fSAndroid Build Coastguard Worker  * std::placeholders::_1 is a placeholder for DumpPool to pass a fd argument.
71*38e8c45fSAndroid Build Coastguard Worker  *
72*38e8c45fSAndroid Build Coastguard Worker  * std::futures returned by `enqueueTask*()` must all have their `get` methods
73*38e8c45fSAndroid Build Coastguard Worker  * called, or have been destroyed before the DumpPool itself is destroyed.
74*38e8c45fSAndroid Build Coastguard Worker  */
75*38e8c45fSAndroid Build Coastguard Worker class DumpPool {
76*38e8c45fSAndroid Build Coastguard Worker   friend class android::os::dumpstate::DumpPoolTest;
77*38e8c45fSAndroid Build Coastguard Worker 
78*38e8c45fSAndroid Build Coastguard Worker   public:
79*38e8c45fSAndroid Build Coastguard Worker     /*
80*38e8c45fSAndroid Build Coastguard Worker      * Creates a thread pool.
81*38e8c45fSAndroid Build Coastguard Worker      *
82*38e8c45fSAndroid Build Coastguard Worker      * |tmp_root| A path to a temporary folder for threads to create temporary
83*38e8c45fSAndroid Build Coastguard Worker      * files.
84*38e8c45fSAndroid Build Coastguard Worker      */
85*38e8c45fSAndroid Build Coastguard Worker     explicit DumpPool(const std::string& tmp_root);
86*38e8c45fSAndroid Build Coastguard Worker 
87*38e8c45fSAndroid Build Coastguard Worker     /*
88*38e8c45fSAndroid Build Coastguard Worker      * Will waits until all threads exit the loop. Destroying DumpPool before destroying the
89*38e8c45fSAndroid Build Coastguard Worker      * associated std::futures created by `enqueueTask*` will cause an abort on Android because
90*38e8c45fSAndroid Build Coastguard Worker      * Android is built with `-fno-exceptions`.
91*38e8c45fSAndroid Build Coastguard Worker      */
92*38e8c45fSAndroid Build Coastguard Worker     ~DumpPool();
93*38e8c45fSAndroid Build Coastguard Worker 
94*38e8c45fSAndroid Build Coastguard Worker     /*
95*38e8c45fSAndroid Build Coastguard Worker      * Starts the threads in the pool.
96*38e8c45fSAndroid Build Coastguard Worker      *
97*38e8c45fSAndroid Build Coastguard Worker      * |thread_counts| the number of threads to start.
98*38e8c45fSAndroid Build Coastguard Worker      */
99*38e8c45fSAndroid Build Coastguard Worker     void start(int thread_counts = MAX_THREAD_COUNT);
100*38e8c45fSAndroid Build Coastguard Worker 
101*38e8c45fSAndroid Build Coastguard Worker     /*
102*38e8c45fSAndroid Build Coastguard Worker      * Adds a task into the queue of the thread pool.
103*38e8c45fSAndroid Build Coastguard Worker      *
104*38e8c45fSAndroid Build Coastguard Worker      * |duration_title| The name of the task. It's also the title of the
105*38e8c45fSAndroid Build Coastguard Worker      * DurationReporter log.
106*38e8c45fSAndroid Build Coastguard Worker      * |f| Callable function to execute the task.
107*38e8c45fSAndroid Build Coastguard Worker      * |args| A list of arguments.
108*38e8c45fSAndroid Build Coastguard Worker      *
109*38e8c45fSAndroid Build Coastguard Worker      * TODO(b/164369078): remove this api to have just one enqueueTask for consistency.
110*38e8c45fSAndroid Build Coastguard Worker      */
111*38e8c45fSAndroid Build Coastguard Worker     template<class F, class... Args>
enqueueTask(const std::string & duration_title,F && f,Args &&...args)112*38e8c45fSAndroid Build Coastguard Worker     std::future<std::string> enqueueTask(const std::string& duration_title, F&& f, Args&&... args) {
113*38e8c45fSAndroid Build Coastguard Worker         std::function<void(void)> func = std::bind(std::forward<F>(f),
114*38e8c45fSAndroid Build Coastguard Worker                 std::forward<Args>(args)...);
115*38e8c45fSAndroid Build Coastguard Worker         auto future = post(duration_title, func);
116*38e8c45fSAndroid Build Coastguard Worker         if (threads_.empty()) {
117*38e8c45fSAndroid Build Coastguard Worker             start();
118*38e8c45fSAndroid Build Coastguard Worker         }
119*38e8c45fSAndroid Build Coastguard Worker         return future;
120*38e8c45fSAndroid Build Coastguard Worker     }
121*38e8c45fSAndroid Build Coastguard Worker 
122*38e8c45fSAndroid Build Coastguard Worker     /*
123*38e8c45fSAndroid Build Coastguard Worker      * Adds a task into the queue of the thread pool. The task takes a file
124*38e8c45fSAndroid Build Coastguard Worker      * descriptor as a parameter to redirect dump results to a temporary file.
125*38e8c45fSAndroid Build Coastguard Worker      *
126*38e8c45fSAndroid Build Coastguard Worker      * |duration_title| The title of the DurationReporter log.
127*38e8c45fSAndroid Build Coastguard Worker      * |f| Callable function to execute the task.
128*38e8c45fSAndroid Build Coastguard Worker      * |args| A list of arguments. A placeholder std::placeholders::_1 as a fd
129*38e8c45fSAndroid Build Coastguard Worker      * argument needs to be included here.
130*38e8c45fSAndroid Build Coastguard Worker      */
enqueueTaskWithFd(const std::string & duration_title,F && f,Args &&...args)131*38e8c45fSAndroid Build Coastguard Worker     template<class F, class... Args> std::future<std::string> enqueueTaskWithFd(
132*38e8c45fSAndroid Build Coastguard Worker             const std::string& duration_title, F&& f, Args&&... args) {
133*38e8c45fSAndroid Build Coastguard Worker         std::function<void(int)> func = std::bind(std::forward<F>(f),
134*38e8c45fSAndroid Build Coastguard Worker                 std::forward<Args>(args)...);
135*38e8c45fSAndroid Build Coastguard Worker         auto future = post(duration_title, func);
136*38e8c45fSAndroid Build Coastguard Worker         if (threads_.empty()) {
137*38e8c45fSAndroid Build Coastguard Worker             start();
138*38e8c45fSAndroid Build Coastguard Worker         }
139*38e8c45fSAndroid Build Coastguard Worker         return future;
140*38e8c45fSAndroid Build Coastguard Worker     }
141*38e8c45fSAndroid Build Coastguard Worker 
142*38e8c45fSAndroid Build Coastguard Worker     /*
143*38e8c45fSAndroid Build Coastguard Worker      * Deletes temporary files created by DumpPool.
144*38e8c45fSAndroid Build Coastguard Worker      */
145*38e8c45fSAndroid Build Coastguard Worker     void deleteTempFiles();
146*38e8c45fSAndroid Build Coastguard Worker 
147*38e8c45fSAndroid Build Coastguard Worker     static const std::string PREFIX_TMPFILE_NAME;
148*38e8c45fSAndroid Build Coastguard Worker 
149*38e8c45fSAndroid Build Coastguard Worker   private:
150*38e8c45fSAndroid Build Coastguard Worker     using Task = std::packaged_task<std::string()>;
151*38e8c45fSAndroid Build Coastguard Worker 
152*38e8c45fSAndroid Build Coastguard Worker     template<class T> void invokeTask(T dump_func, const std::string& duration_title, int out_fd);
153*38e8c45fSAndroid Build Coastguard Worker 
154*38e8c45fSAndroid Build Coastguard Worker     template<class T>
post(const std::string & duration_title,T dump_func)155*38e8c45fSAndroid Build Coastguard Worker     std::future<std::string> post(const std::string& duration_title, T dump_func) {
156*38e8c45fSAndroid Build Coastguard Worker         Task packaged_task([=]() {
157*38e8c45fSAndroid Build Coastguard Worker             std::unique_ptr<TmpFile> tmp_file_ptr = createTempFile();
158*38e8c45fSAndroid Build Coastguard Worker             if (!tmp_file_ptr) {
159*38e8c45fSAndroid Build Coastguard Worker                 return std::string("");
160*38e8c45fSAndroid Build Coastguard Worker             }
161*38e8c45fSAndroid Build Coastguard Worker             invokeTask(dump_func, duration_title, tmp_file_ptr->fd.get());
162*38e8c45fSAndroid Build Coastguard Worker             fsync(tmp_file_ptr->fd.get());
163*38e8c45fSAndroid Build Coastguard Worker             return std::string(tmp_file_ptr->path);
164*38e8c45fSAndroid Build Coastguard Worker         });
165*38e8c45fSAndroid Build Coastguard Worker         std::unique_lock lock(lock_);
166*38e8c45fSAndroid Build Coastguard Worker         auto future = packaged_task.get_future();
167*38e8c45fSAndroid Build Coastguard Worker         tasks_.push(std::move(packaged_task));
168*38e8c45fSAndroid Build Coastguard Worker         condition_variable_.notify_one();
169*38e8c45fSAndroid Build Coastguard Worker         return future;
170*38e8c45fSAndroid Build Coastguard Worker     }
171*38e8c45fSAndroid Build Coastguard Worker 
172*38e8c45fSAndroid Build Coastguard Worker     typedef struct {
173*38e8c45fSAndroid Build Coastguard Worker       android::base::unique_fd fd;
174*38e8c45fSAndroid Build Coastguard Worker       char path[1024];
175*38e8c45fSAndroid Build Coastguard Worker     } TmpFile;
176*38e8c45fSAndroid Build Coastguard Worker 
177*38e8c45fSAndroid Build Coastguard Worker     std::unique_ptr<TmpFile> createTempFile();
178*38e8c45fSAndroid Build Coastguard Worker     void deleteTempFiles(const std::string& folder);
179*38e8c45fSAndroid Build Coastguard Worker     void setThreadName(const pthread_t thread, int id);
180*38e8c45fSAndroid Build Coastguard Worker     void loop();
181*38e8c45fSAndroid Build Coastguard Worker 
182*38e8c45fSAndroid Build Coastguard Worker     /*
183*38e8c45fSAndroid Build Coastguard Worker      * For test purpose only. Enables or disables logging duration of the task.
184*38e8c45fSAndroid Build Coastguard Worker      *
185*38e8c45fSAndroid Build Coastguard Worker      * |log_duration| if true, DurationReporter is initiated to log duration of
186*38e8c45fSAndroid Build Coastguard Worker      * the task.
187*38e8c45fSAndroid Build Coastguard Worker      */
188*38e8c45fSAndroid Build Coastguard Worker     void setLogDuration(bool log_duration);
189*38e8c45fSAndroid Build Coastguard Worker 
190*38e8c45fSAndroid Build Coastguard Worker   private:
191*38e8c45fSAndroid Build Coastguard Worker     static const int MAX_THREAD_COUNT = 4;
192*38e8c45fSAndroid Build Coastguard Worker 
193*38e8c45fSAndroid Build Coastguard Worker     /* A path to a temporary folder for threads to create temporary files. */
194*38e8c45fSAndroid Build Coastguard Worker     std::string tmp_root_;
195*38e8c45fSAndroid Build Coastguard Worker     bool shutdown_;
196*38e8c45fSAndroid Build Coastguard Worker     bool log_duration_; // For test purpose only, the default value is true.
197*38e8c45fSAndroid Build Coastguard Worker     std::mutex lock_;  // A lock for the tasks_.
198*38e8c45fSAndroid Build Coastguard Worker     std::condition_variable condition_variable_;
199*38e8c45fSAndroid Build Coastguard Worker 
200*38e8c45fSAndroid Build Coastguard Worker     std::vector<std::thread> threads_;
201*38e8c45fSAndroid Build Coastguard Worker     std::queue<Task> tasks_;
202*38e8c45fSAndroid Build Coastguard Worker 
203*38e8c45fSAndroid Build Coastguard Worker     DISALLOW_COPY_AND_ASSIGN(DumpPool);
204*38e8c45fSAndroid Build Coastguard Worker };
205*38e8c45fSAndroid Build Coastguard Worker 
206*38e8c45fSAndroid Build Coastguard Worker }  // namespace dumpstate
207*38e8c45fSAndroid Build Coastguard Worker }  // namespace os
208*38e8c45fSAndroid Build Coastguard Worker }  // namespace android
209*38e8c45fSAndroid Build Coastguard Worker 
210*38e8c45fSAndroid Build Coastguard Worker #endif //FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
211