• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "status.h"
16 
17 #ifdef _WIN32
18 #include "win32port.h"
19 #else
20 #ifndef __STDC_FORMAT_MACROS
21 #define __STDC_FORMAT_MACROS
22 #endif
23 #include <cinttypes>
24 #endif
25 
26 #include <stdarg.h>
27 #include <stdlib.h>
28 
29 #ifdef _WIN32
30 #include <fcntl.h>
31 #include <io.h>
32 #endif
33 
34 #include "debug_flags.h"
35 
36 using namespace std;
37 
StatusPrinter(const BuildConfig & config)38 StatusPrinter::StatusPrinter(const BuildConfig& config)
39         : config_(config), started_edges_(0), finished_edges_(0), total_edges_(0),
40             running_edges_(0), progress_status_format_(NULL),
41             current_rate_(config.parallelism) {
42     // Don't do anything fancy in verbose mode.
43     if (config_.verbosity != BuildConfig::NORMAL)
44         printer_.set_smart_terminal(false);
45 
46     progress_status_format_ = getenv("NINJA_STATUS");
47     if (!progress_status_format_)
48         progress_status_format_ = "[%f/%t] ";
49 }
50 
EdgeAddedToPlan(const Edge * edge)51 void StatusPrinter::EdgeAddedToPlan(const Edge* edge) {
52     ++total_edges_;
53 
54     // Do we know how long did this edge take last time?
55     if (edge->prev_elapsed_time_millis != -1) {
56         ++eta_predictable_edges_total_;
57         ++eta_predictable_edges_remaining_;
58         eta_predictable_cpu_time_total_millis_ += edge->prev_elapsed_time_millis;
59         eta_predictable_cpu_time_remaining_millis_ +=
60                 edge->prev_elapsed_time_millis;
61     } else
62         ++eta_unpredictable_edges_remaining_;
63 }
64 
EdgeRemovedFromPlan(const Edge * edge)65 void StatusPrinter::EdgeRemovedFromPlan(const Edge* edge) {
66     --total_edges_;
67 
68     // Do we know how long did this edge take last time?
69     if (edge->prev_elapsed_time_millis != -1) {
70         --eta_predictable_edges_total_;
71         --eta_predictable_edges_remaining_;
72         eta_predictable_cpu_time_total_millis_ -= edge->prev_elapsed_time_millis;
73         eta_predictable_cpu_time_remaining_millis_ -=
74                 edge->prev_elapsed_time_millis;
75     } else
76         --eta_unpredictable_edges_remaining_;
77 }
78 
BuildEdgeStarted(const Edge * edge,int64_t start_time_millis)79 void StatusPrinter::BuildEdgeStarted(const Edge* edge,
80                                                                           int64_t start_time_millis) {
81     ++started_edges_;
82     ++running_edges_;
83     time_millis_ = start_time_millis;
84 
85     if (edge->use_console() || printer_.is_smart_terminal())
86         PrintStatus(edge, start_time_millis);
87 
88     if (edge->use_console())
89         printer_.SetConsoleLocked(true);
90 }
91 
RecalculateProgressPrediction()92 void StatusPrinter::RecalculateProgressPrediction() {
93     time_predicted_percentage_ = 0.0;
94 
95     // Sometimes, the previous and actual times may be wildly different.
96     // For example, the previous build may have been fully recovered from ccache,
97     // so it was blazing fast, while the new build no longer gets hits from ccache
98     // for whatever reason, so it actually compiles code, which takes much longer.
99     // We should detect such cases, and avoid using "wrong" previous times.
100 
101     // Note that we will only use the previous times if there are edges with
102     // previous time knowledge remaining.
103     bool use_previous_times = eta_predictable_edges_remaining_ &&
104                                                         eta_predictable_cpu_time_remaining_millis_;
105 
106     // Iff we have sufficient statistical information for the current run,
107     // that is, if we have took at least 15 sec AND finished at least 5% of edges,
108     // we can check whether our performance so far matches the previous one.
109     if (use_previous_times && total_edges_ && finished_edges_ &&
110         (time_millis_ >= 15 * 1e3) &&
111         (((double)finished_edges_ / total_edges_) >= 0.05)) {
112         // Over the edges we've just run, how long did they take on average?
113         double actual_average_cpu_time_millis =
114             (double)cpu_time_millis_ / finished_edges_;
115         // What is the previous average, for the edges with such knowledge?
116         double previous_average_cpu_time_millis =
117             (double)eta_predictable_cpu_time_total_millis_ /
118             eta_predictable_edges_total_;
119 
120         double ratio = std::max(previous_average_cpu_time_millis,
121             actual_average_cpu_time_millis) /
122             std::min(previous_average_cpu_time_millis,
123             actual_average_cpu_time_millis);
124 
125         // Let's say that the average times should differ by less than 10x
126         use_previous_times = ratio < 10;
127     }
128 
129     int edges_with_known_runtime = finished_edges_;
130     if (use_previous_times)
131         edges_with_known_runtime += eta_predictable_edges_remaining_;
132     if (edges_with_known_runtime == 0)
133         return;
134 
135     int edges_with_unknown_runtime = use_previous_times
136         ? eta_unpredictable_edges_remaining_
137         : (total_edges_ - finished_edges_);
138 
139     // Given the time elapsed on the edges we've just run,
140     // and the runtime of the edges for which we know previous runtime,
141     // what's the edge's average runtime?
142     int64_t edges_known_runtime_total_millis = cpu_time_millis_;
143     if (use_previous_times)
144         edges_known_runtime_total_millis +=
145             eta_predictable_cpu_time_remaining_millis_;
146 
147     double average_cpu_time_millis =
148         (double)edges_known_runtime_total_millis / edges_with_known_runtime;
149 
150     // For the edges for which we do not have the previous runtime,
151     // let's assume that their average runtime is the same as for the other edges,
152     // and we therefore can predict their remaining runtime.
153     double unpredictable_cpu_time_remaining_millis =
154             average_cpu_time_millis * edges_with_unknown_runtime;
155 
156     // And therefore we can predict the remaining and total runtimes.
157     double total_cpu_time_remaining_millis =
158         unpredictable_cpu_time_remaining_millis;
159     if (use_previous_times)
160         total_cpu_time_remaining_millis +=
161             eta_predictable_cpu_time_remaining_millis_;
162     double total_cpu_time_millis =
163         cpu_time_millis_ + total_cpu_time_remaining_millis;
164     if (total_cpu_time_millis == 0.0)
165         return;
166 
167     // After that we can tell how much work we've completed, in time units.
168     time_predicted_percentage_ = cpu_time_millis_ / total_cpu_time_millis;
169 }
170 
BuildEdgeFinished(Edge * edge,int64_t start_time_millis,int64_t end_time_millis,bool success,const string & output)171 void StatusPrinter::BuildEdgeFinished(Edge* edge, int64_t start_time_millis,
172                                                                             int64_t end_time_millis, bool success,
173                                                                             const string& output) {
174     time_millis_ = end_time_millis;
175     ++finished_edges_;
176 
177     int64_t elapsed = end_time_millis - start_time_millis;
178     cpu_time_millis_ += elapsed;
179 
180     // Do we know how long did this edge take last time?
181     if (edge->prev_elapsed_time_millis != -1) {
182         --eta_predictable_edges_remaining_;
183         eta_predictable_cpu_time_remaining_millis_ -=
184             edge->prev_elapsed_time_millis;
185     } else
186         --eta_unpredictable_edges_remaining_;
187 
188     if (edge->use_console())
189         printer_.SetConsoleLocked(false);
190 
191     if (config_.verbosity == BuildConfig::QUIET)
192         return;
193 
194     if (!edge->use_console())
195         PrintStatus(edge, end_time_millis);
196 
197     --running_edges_;
198 
199     // Print the command that is spewing before printing its output.
200     if (!success) {
201         string outputs;
202         for (vector<Node*>::const_iterator o = edge->outputs_.begin();
203                 o != edge->outputs_.end(); ++o)
204             outputs += (*o)->path() + " ";
205 
206         if (printer_.supports_color()) {
207             printer_.PrintOnNewLine("\x1B[31m" "FAILED: " "\x1B[0m" + outputs + "\n");
208         } else {
209             printer_.PrintOnNewLine("FAILED: " + outputs + "\n");
210         }
211         printer_.PrintOnNewLine(edge->EvaluateCommand() + "\n");
212     }
213 
214     if (!output.empty()) {
215         // ninja sets stdout and stderr of subprocesses to a pipe, to be able to
216         // check if the output is empty. Some compilers, e.g. clang, check
217         // isatty(stderr) to decide if they should print colored output.
218         // To make it possible to use colored output with ninja, subprocesses should
219         // be run with a flag that forces them to always print color escape codes.
220         // To make sure these escape codes don't show up in a file if ninja's output
221         // is piped to a file, ninja strips ansi escape codes again if it's not
222         // writing to a |smart_terminal_|.
223         // (Launching subprocesses in pseudo ttys doesn't work because there are
224         // only a few hundred available on some systems, and ninja can launch
225         // thousands of parallel compile commands.)
226         string final_output;
227         if (!printer_.supports_color())
228             final_output = StripAnsiEscapeCodes(output);
229         else
230             final_output = output;
231 
232 #ifdef _WIN32
233     // Fix extra CR being added on Windows, writing out CR CR LF (#773)
234     _setmode(_fileno(stdout), _O_BINARY);  // Begin Windows extra CR fix
235 #endif
236 
237     printer_.PrintOnNewLine(final_output);
238 
239 #ifdef _WIN32
240     _setmode(_fileno(stdout), _O_TEXT);  // End Windows extra CR fix
241 #endif
242     }
243 }
244 
BuildLoadDyndeps()245 void StatusPrinter::BuildLoadDyndeps() {
246     // The DependencyScan calls EXPLAIN() to print lines explaining why
247     // it considers a portion of the graph to be out of date.  Normally
248     // this is done before the build starts, but our caller is about to
249     // load a dyndep file during the build.  Doing so may generate more
250     // explanation lines (via fprintf directly to stderr), but in an
251     // interactive console the cursor is currently at the end of a status
252     // line.  Start a new line so that the first explanation does not
253     // append to the status line.  After the explanations are done a
254     // new build status line will appear.
255     if (g_explaining)
256         printer_.PrintOnNewLine("");
257 }
258 
BuildStarted()259 void StatusPrinter::BuildStarted() {
260     started_edges_ = 0;
261     finished_edges_ = 0;
262     running_edges_ = 0;
263 }
264 
BuildFinished()265 void StatusPrinter::BuildFinished() {
266     printer_.SetConsoleLocked(false);
267     printer_.PrintOnNewLine("");
268 }
269 
FormatProgressStatus(const char * progress_status_format,int64_t time_millis) const270 string StatusPrinter::FormatProgressStatus(const char* progress_status_format,
271                                                                                       int64_t time_millis) const {
272     string out;
273     char buf[32];
274     for (const char* s = progress_status_format; *s != '\0'; ++s) {
275         if (*s == '%') {
276             ++s;
277             switch (*s) {
278             case '%':
279                 out.push_back('%');
280                 break;
281 
282                 // Started edges.
283             case 's':
284                 snprintf(buf, sizeof(buf), "%d", started_edges_);
285                 out += buf;
286                 break;
287 
288                 // Total edges.
289             case 't':
290                 snprintf(buf, sizeof(buf), "%d", total_edges_);
291                 out += buf;
292                 break;
293 
294                 // Running edges.
295             case 'r': {
296                 snprintf(buf, sizeof(buf), "%d", running_edges_);
297                 out += buf;
298                 break;
299             }
300 
301                 // Unstarted edges.
302             case 'u':
303                 snprintf(buf, sizeof(buf), "%d", total_edges_ - started_edges_);
304                 out += buf;
305                 break;
306 
307                 // Finished edges.
308             case 'f':
309                 snprintf(buf, sizeof(buf), "%d", finished_edges_);
310                 out += buf;
311                 break;
312 
313                 // Overall finished edges per second.
314             case 'o':
315                 SnprintfRate(finished_edges_ / (time_millis_ / 1e3), buf, "%.1f");
316                 out += buf;
317                 break;
318 
319                 // Current rate, average over the last '-j' jobs.
320             case 'c':
321                 current_rate_.UpdateRate(finished_edges_, time_millis_);
322                 SnprintfRate(current_rate_.rate(), buf, "%.1f");
323                 out += buf;
324                 break;
325 
326                 // Percentage of edges completed
327             case 'p': {
328                 int percent = 0;
329                 if (finished_edges_ != 0 && total_edges_ != 0)
330                     percent = (100 * finished_edges_) / total_edges_;
331                 snprintf(buf, sizeof(buf), "%3i%%", percent);
332                 out += buf;
333                 break;
334             }
335 
336 #define FORMAT_TIME_HMMSS(t)                                                \
337     "%" PRId64 ":%02" PRId64 ":%02" PRId64 "", (t) / 3600, ((t) % 3600) / 60, \
338             (t) % 60
339 #define FORMAT_TIME_MMSS(t) "%02" PRId64 ":%02" PRId64 "", (t) / 60, (t) % 60
340 
341                 // Wall time
342             case 'e':  // elapsed, seconds
343             case 'w':  // elapsed, human-readable
344             case 'E':  // ETA, seconds
345             case 'W':  // ETA, human-readable
346             {
347                 double elapsed_sec = time_millis_ / 1e3;
348                 double eta_sec = -1;  // To be printed as "?".
349                 if (time_predicted_percentage_ != 0.0) {
350                     // So, we know that we've spent time_millis_ wall clock,
351                     // and that is time_predicted_percentage_ percent.
352                     // How much time will we need to complete 100%?
353                     double total_wall_time = time_millis_ / time_predicted_percentage_;
354                     // Naturally, that gives us the time remaining.
355                     eta_sec = (total_wall_time - time_millis_) / 1e3;
356                 }
357 
358                 const bool print_with_hours =
359                     elapsed_sec >= 60 * 60 || eta_sec >= 60 * 60;
360 
361                 double sec = -1;
362                 switch (*s) {
363                 case 'e':  // elapsed, seconds
364                 case 'w':  // elapsed, human-readable
365                     sec = elapsed_sec;
366                     break;
367                 case 'E':  // ETA, seconds
368                 case 'W':  // ETA, human-readable
369                     sec = eta_sec;
370                     break;
371                 }
372 
373                 if (sec < 0)
374                     snprintf(buf, sizeof(buf), "?");
375                 else {
376                     switch (*s) {
377                     case 'e':  // elapsed, seconds
378                     case 'E':  // ETA, seconds
379                         snprintf(buf, sizeof(buf), "%.3f", sec);
380                         break;
381                     case 'w':  // elapsed, human-readable
382                     case 'W':  // ETA, human-readable
383                         if (print_with_hours)
384                             snprintf(buf, sizeof(buf), FORMAT_TIME_HMMSS((int64_t)sec));
385                         else
386                             snprintf(buf, sizeof(buf), FORMAT_TIME_MMSS((int64_t)sec));
387                         break;
388                     }
389                 }
390                 out += buf;
391                 break;
392             }
393 
394             // Percentage of time spent out of the predicted time total
395             case 'P': {
396                 snprintf(buf, sizeof(buf), "%3i%%",
397                     (int)(100. * time_predicted_percentage_));
398                 out += buf;
399                 break;
400             }
401 
402             default:
403                 Fatal("unknown placeholder '%%%c' in $NINJA_STATUS", *s);
404                 return "";
405             }
406         } else {
407             out.push_back(*s);
408         }
409     }
410 
411     return out;
412 }
413 
PrintStatus(const Edge * edge,int64_t time_millis)414 void StatusPrinter::PrintStatus(const Edge* edge, int64_t time_millis) {
415     if (config_.verbosity == BuildConfig::QUIET
416         || config_.verbosity == BuildConfig::NO_STATUS_UPDATE)
417         return;
418 
419     RecalculateProgressPrediction();
420 
421     bool force_full_command = config_.verbosity == BuildConfig::VERBOSE;
422 
423     string to_print = edge->GetBinding("description");
424     if (to_print.empty() || force_full_command)
425         to_print = edge->GetBinding("command");
426 
427     to_print = FormatProgressStatus(progress_status_format_, time_millis)
428         + to_print;
429 
430     printer_.Print(to_print,force_full_command ? LinePrinter::FULL : LinePrinter::ELIDE);
431 }
432 
Warning(const char * msg,...)433 void StatusPrinter::Warning(const char* msg, ...) {
434     va_list ap;
435     va_start(ap, msg);
436     ::Warning(msg, ap);
437     va_end(ap);
438 }
439 
Error(const char * msg,...)440 void StatusPrinter::Error(const char* msg, ...) {
441     va_list ap;
442     va_start(ap, msg);
443     ::Error(msg, ap);
444     va_end(ap);
445 }
446 
Info(const char * msg,...)447 void StatusPrinter::Info(const char* msg, ...) {
448     va_list ap;
449     va_start(ap, msg);
450     ::Info(msg, ap);
451     va_end(ap);
452 }
453