@@ -70,10 +70,13 @@ static cl::opt<std::string> OutIncrement{
70
70
" pass." ),
71
71
cl::init (" " ), cl::value_desc (" R" )};
72
72
73
- static cl::opt<bool > ExecuteInParallel{
73
+ static cl::opt<unsigned int > ExecuteInParallel{
74
74
" parallel-exec" ,
75
- cl::desc (" Enable launching input commands in parallel mode" ),
76
- cl::init (false )};
75
+ cl::Optional,
76
+ cl::init (1 ),
77
+ cl::desc (" Specify the number of threads for launching input commands in "
78
+ " parallel mode" ),
79
+ };
77
80
78
81
static void error (const Twine &Msg) {
79
82
errs () << " llvm-foreach: " << Msg << ' \n ' ;
@@ -85,6 +88,31 @@ static void error(std::error_code EC, const Twine &Prefix) {
85
88
error (Prefix + " : " + EC.message ());
86
89
}
87
90
91
+ // With WaitUntilTerminates=false this function just goes through the all
92
+ // submitted jobs to check if one of them has finished.
93
+ // TODO: give a proper naming as this function doesn't wait for jobs with
94
+ // WaitUntilTerminates=false
95
+ void waitJobsToBeFinished (std::list<sys::ProcessInfo> &JobsSubmitted, int &Res,
96
+ bool WaitUntilTerminates = true ) {
97
+ std::string ErrMsg;
98
+ auto It = JobsSubmitted.begin ();
99
+ while (It != JobsSubmitted.end ()) {
100
+ sys::ProcessInfo WaitResult =
101
+ sys::Wait (*It, 0 , /* WaitUntilTerminates*/ WaitUntilTerminates, &ErrMsg);
102
+
103
+ // Check if the job has finished (PID will be 0 if it's not).
104
+ if (!WaitUntilTerminates && !WaitResult.Pid ) {
105
+ It++;
106
+ continue ;
107
+ }
108
+ if (WaitResult.ReturnCode != 0 ) {
109
+ errs () << " llvm-foreach: " << ErrMsg << ' \n ' ;
110
+ Res = WaitResult.ReturnCode ;
111
+ }
112
+ It = JobsSubmitted.erase (It);
113
+ }
114
+ }
115
+
88
116
int main (int argc, char **argv) {
89
117
cl::ParseCommandLineOptions (
90
118
argc, argv,
@@ -166,6 +194,13 @@ int main(int argc, char **argv) {
166
194
PrevNumOfLines = FileLists[i].size ();
167
195
}
168
196
197
+ if (!ExecuteInParallel)
198
+ error (" Number of parallel threads should be a positive integer" );
199
+ if (ExecuteInParallel > 16 ) {
200
+ ExecuteInParallel = 16 ;
201
+ errs () << " llvm-foreach: adjusted number of threads to 16 (max available)" ;
202
+ }
203
+
169
204
std::error_code EC;
170
205
raw_fd_ostream OS{OutputFileList, EC, sys::fs::OpenFlags::OF_None};
171
206
if (!OutputFileList.empty ())
@@ -176,7 +211,7 @@ int main(int argc, char **argv) {
176
211
std::string IncOutArg;
177
212
std::vector<std::string> ResInArgs (InReplaceArgs.size ());
178
213
std::string ResFileList = " " ;
179
- std::list<sys::ProcessInfo> CommandsStarted ;
214
+ std::list<sys::ProcessInfo> JobsSubmitted ;
180
215
for (size_t j = 0 ; j != FileLists[0 ].size (); ++j) {
181
216
for (size_t i = 0 ; i < InReplaceArgs.size (); ++i) {
182
217
ArgumentReplace CurReplace = InReplaceArgs[i];
@@ -228,34 +263,17 @@ int main(int argc, char **argv) {
228
263
Args[OutIncrementArg.ArgNum ] = IncOutArg;
229
264
}
230
265
231
- std::string ErrMsg;
232
- if (ExecuteInParallel) {
233
- CommandsStarted.emplace_back (sys::ExecuteNoWait (
234
- Prog, Args, /* Env=*/ None, /* Redirects=*/ None, /* MemoryLimit=*/ 0 ));
235
- continue ;
236
- }
266
+ // Do not start execution of a new job until previous one(s) are finished,
267
+ // if the maximum number of parallel workers is reached.
268
+ while (JobsSubmitted.size () == ExecuteInParallel)
269
+ waitJobsToBeFinished (JobsSubmitted, Res, /* WaitUntilTerminates*/ false );
237
270
238
- int Result =
239
- sys::ExecuteAndWait (Prog, Args, /* Env=*/ None, /* Redirects=*/ None,
240
- /* SecondsToWait=*/ 0 , /* MemoryLimit=*/ 0 , &ErrMsg);
241
- if (Result != 0 ) {
242
- errs () << " llvm-foreach: " << ErrMsg << ' \n ' ;
243
- Res = Result;
244
- }
271
+ JobsSubmitted.emplace_back (sys::ExecuteNoWait (
272
+ Prog, Args, /* Env=*/ None, /* Redirects=*/ None, /* MemoryLimit=*/ 0 ));
245
273
}
246
274
247
275
// Wait for all commands to be executed.
248
- std::string ErrMsg;
249
- auto It = CommandsStarted.begin ();
250
- while (It != CommandsStarted.end ()) {
251
- sys::ProcessInfo WaitResult =
252
- sys::Wait (*It, 0 , /* WaitUntilTerminates*/ true , &ErrMsg);
253
- if (WaitResult.ReturnCode != 0 ) {
254
- errs () << " llvm-foreach: " << ErrMsg << ' \n ' ;
255
- Res = WaitResult.ReturnCode ;
256
- }
257
- It = CommandsStarted.erase (It);
258
- }
276
+ waitJobsToBeFinished (JobsSubmitted, Res, /* WaitUntilTerminates*/ true );
259
277
260
278
if (!OutputFileList.empty ()) {
261
279
OS.close ();
0 commit comments