summaryrefslogtreecommitdiffstats
path: root/src/status.h
blob: a1a8fddeaecb57c2bbbf13ca2a54fe6c5a941189 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef NINJA_STATUS_H_
#define NINJA_STATUS_H_

#include <map>
#include <string>

#include "build.h"
#include "line_printer.h"

/// Abstract interface to object that tracks the status of a build:
/// completion fraction, printing updates.
struct Status {
  virtual void EdgeAddedToPlan(const Edge* edge) = 0;
  virtual void EdgeRemovedFromPlan(const Edge* edge) = 0;
  virtual void BuildEdgeStarted(const Edge* edge,
                                int64_t start_time_millis) = 0;
  virtual void BuildEdgeFinished(Edge* edge, int64_t start_time_millis,
                                 int64_t end_time_millis, bool success,
                                 const std::string& output) = 0;
  virtual void BuildLoadDyndeps() = 0;
  virtual void BuildStarted() = 0;
  virtual void BuildFinished() = 0;

  virtual void Info(const char* msg, ...) = 0;
  virtual void Warning(const char* msg, ...) = 0;
  virtual void Error(const char* msg, ...) = 0;

  virtual ~Status() { }
};

/// Implementation of the Status interface that prints the status as
/// human-readable strings to stdout
struct StatusPrinter : Status {
  explicit StatusPrinter(const BuildConfig& config);

  /// Callbacks for the Plan to notify us about adding/removing Edge's.
  virtual void EdgeAddedToPlan(const Edge* edge);
  virtual void EdgeRemovedFromPlan(const Edge* edge);

  virtual void BuildEdgeStarted(const Edge* edge, int64_t start_time_millis);
  virtual void BuildEdgeFinished(Edge* edge, int64_t start_time_millis,
                                 int64_t end_time_millis, bool success,
                                 const std::string& output);
  virtual void BuildLoadDyndeps();
  virtual void BuildStarted();
  virtual void BuildFinished();

  virtual void Info(const char* msg, ...);
  virtual void Warning(const char* msg, ...);
  virtual void Error(const char* msg, ...);

  virtual ~StatusPrinter() { }

  /// Format the progress status string by replacing the placeholders.
  /// See the user manual for more information about the available
  /// placeholders.
  /// @param progress_status_format The format of the progress status.
  /// @param status The status of the edge.
  std::string FormatProgressStatus(const char* progress_status_format,
                                   int64_t time_millis) const;

 private:
  void PrintStatus(const Edge* edge, int64_t time_millis);

  const BuildConfig& config_;

  int started_edges_, finished_edges_, total_edges_, running_edges_;

  /// How much wall clock elapsed so far?
  int64_t time_millis_ = 0;

  /// How much cpu clock elapsed so far?
  int64_t cpu_time_millis_ = 0;

  /// What percentage of predicted total time have elapsed already?
  double time_predicted_percentage_ = 0.0;

  /// Out of all the edges, for how many do we know previous time?
  int eta_predictable_edges_total_ = 0;
  /// And how much time did they all take?
  int64_t eta_predictable_cpu_time_total_millis_ = 0;

  /// Out of all the non-finished edges, for how many do we know previous time?
  int eta_predictable_edges_remaining_ = 0;
  /// And how much time will they all take?
  int64_t eta_predictable_cpu_time_remaining_millis_ = 0;

  /// For how many edges we don't know the previous run time?
  int eta_unpredictable_edges_remaining_ = 0;

  void RecalculateProgressPrediction();

  /// Prints progress output.
  LinePrinter printer_;

  /// The custom progress status format to use.
  const char* progress_status_format_;

  template<size_t S>
  void SnprintfRate(double rate, char(&buf)[S], const char* format) const {
    if (rate == -1)
      snprintf(buf, S, "?");
    else
      snprintf(buf, S, format, rate);
  }

  struct SlidingRateInfo {
    SlidingRateInfo(int n) : rate_(-1), N(n), last_update_(-1) {}

    double rate() { return rate_; }

    void UpdateRate(int update_hint, int64_t time_millis) {
      if (update_hint == last_update_)
        return;
      last_update_ = update_hint;

      if (times_.size() == N)
        times_.pop();
      times_.push(time_millis);
      if (times_.back() != times_.front())
        rate_ = times_.size() / ((times_.back() - times_.front()) / 1e3);
    }

  private:
    double rate_;
    const size_t N;
    std::queue<double> times_;
    int last_update_;
  };

  mutable SlidingRateInfo current_rate_;
};

#endif // NINJA_STATUS_H_