blob: a1059847a36da19d960b2e947eacee1256adaef4 [file] [log] [blame]
// Copyright 2011 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_METRICS_H_
#define NINJA_METRICS_H_
#include <memory>
#include <string>
#include <vector>
#include "string_piece.h"
#include "util.h" // For int64_t.
/// The Metrics module is used for the debug mode that dumps timing stats of
/// various actions. To use, see METRIC_RECORD below.
/// A single metrics we're tracking, like "depfile load time".
struct Metric {
Metric(StringPiece name) : name(name.AsString()) {}
std::string name;
/// Number of times we've hit the code path.
int count = 0;
/// Total time (in platform-dependent units) we've spent on the code path.
int64_t sum = 0;
};
/// A scoped object for recording a metric across the body of a function.
/// Used by the METRIC_RECORD macro.
struct ScopedMetric {
explicit ScopedMetric(Metric* metric);
~ScopedMetric();
private:
Metric* metric_;
/// Timestamp when the measurement started.
/// Value is platform-dependent.
int64_t start_;
};
/// A set of metrics scoped to a given domain, e.g. manifest loading, or
/// build invocation.
struct MetricsDomain {
Metric* NewMetric(StringPiece name);
/// Reset all Metric instances in this domain.
void Reset();
/// Compute the max width of all metric names in this domain.
/// If |cur_max_width| is not 0, then ensure the result is always greater
/// or equal to it, which is useful when combining several domain reports.
int ComputeMaxNameWidth(int cur_max_width = 0);
/// Print a one-line table banner describing metric details.
static void PrintBanner(int max_width);
/// Print a summary of all metrics to stdout, without any banner.
void Print(int max_width = 0);
/// Print a summary report for just this domain to stdout.
void Report();
private:
std::vector<std::unique_ptr<Metric>> metrics_;
};
/// The set of Ninja metrics domains.
struct Metrics {
/// Print a summary report for all domains to stdout.
void Report();
MetricsDomain load_;
MetricsDomain build_;
};
/// Get the current time as relative to some epoch.
/// Epoch varies between platforms; only useful for measuring elapsed time.
int64_t GetTimeMillis();
/// A simple stopwatch which returns the time
/// in seconds since Restart() was called.
struct Stopwatch {
public:
Stopwatch() : started_(0) {}
/// Seconds since Restart() call.
double Elapsed() const;
void Restart() { started_ = NowRaw(); }
private:
uint64_t started_;
// Return the current time using the native frequency of the high resolution
// timer.
uint64_t NowRaw() const;
};
/// The primary interface to metrics. Use METRIC_RECORD("foobar") at the top
/// of a function to get timing stats recorded for each call of the function.
/// This creates a metric in the "build" domain, for operations performed
/// when loading the manifest, use METRIC_RECORD_LOAD() instead.
#define METRIC_RECORD(name) \
static Metric* metrics_h_metric = \
g_metrics ? g_metrics->build_.NewMetric(name) : NULL; \
ScopedMetric metrics_h_scoped(metrics_h_metric);
/// A variant of METRIC_RECORD() for timing manifest loading operations.
#define METRIC_RECORD_LOAD(name) \
static Metric* metrics_h_metric = \
g_metrics ? g_metrics->load_.NewMetric(name) : NULL; \
ScopedMetric metrics_h_scoped(metrics_h_metric);
/// A variant of METRIC_RECORD that doesn't record anything if |condition|
/// is false.
#define METRIC_RECORD_IF(name, condition) \
static Metric* metrics_h_metric = \
g_metrics ? g_metrics->build_.NewMetric(name) : NULL; \
ScopedMetric metrics_h_scoped((condition) ? metrics_h_metric : NULL);
/// A variant of METRIC_RECORD_IF for timing manifest loading operations.
#define METRIC_RECORD_LOAD_IF(name, condition) \
static Metric* metrics_h_metric = \
g_metrics ? g_metrics->load_.NewMetric(name) : NULL; \
ScopedMetric metrics_h_scoped((condition) ? metrics_h_metric : NULL);
extern Metrics* g_metrics;
#endif // NINJA_METRICS_H_