blob: 83df1fa9030d0f46a6fa658fe72184fe87bfa9a5 [file]
// Copyright 2017 The Goma Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "counterz.h"
#include <algorithm>
#include <glog/logging.h>
#include "absl/strings/match.h"
#include "file_helper.h"
#include "google/protobuf/util/json_util.h"
namespace devtools_goma {
struct CounterStat {
std::string name;
int64_t count;
absl::Duration time;
};
void CounterInfo::Inc(absl::Duration time) {
counter_.Add(1);
// This must be kept as an integer number of nanoseconds because
// total_time_in_ns_ is an atomic integer counter.
total_time_in_ns_.Add(absl::ToInt64Nanoseconds(time));
}
void CounterInfo::Dump(CounterStat* stat) const {
stat->name = location_ + "(" + funcname_ + ":" + name_ + ")";
stat->count = counter_.value();
stat->time = absl::Nanoseconds(total_time_in_ns_.value());
}
void CounterInfo::DumpToProto(CounterzStat* counterz) const {
counterz->set_name(name_);
counterz->set_function_name(funcname_);
counterz->set_location(location_);
counterz->set_total_count(counter_.value());
counterz->set_total_time_ns(total_time_in_ns_.value());
}
void Counterz::DumpToJson(Json::Value* json) const {
std::vector<CounterStat> stats(counters_.size());
{
AUTOLOCK(lock, &mu_);
for (size_t i = 0; i < counters_.size(); ++i) {
counters_[i]->Dump(&stats[i]);
}
}
std::sort(stats.begin(), stats.end(),
[](const CounterStat& l, const CounterStat& r) {
return l.time > r.time;
});
*json = Json::Value(Json::arrayValue);
for (const auto& stat : stats) {
Json::Value value;
value["name"] = stat.name;
value["count"] = Json::Int64(stat.count);
value["total time"] = absl::FormatDuration(stat.time);
value["average time"] =
absl::FormatDuration(stat.time / std::max<int64_t>(stat.count, 1));
json->append(std::move(value));
}
}
void Counterz::DumpToProto(CounterzStats* counters) const {
AUTOLOCK(lock, &mu_);
for (size_t i = 0; i < counters_.size(); ++i) {
counters_[i]->DumpToProto(counters->add_counterz_stats());
}
}
Counterz* Counterz::instance_;
/* static */
void Counterz::Init() {
CHECK(instance_ == nullptr);
instance_ = new Counterz;
}
/* static */
void Counterz::Dump(const std::string& filename) {
CHECK(instance_ != nullptr);
CounterzStats counterz;
instance_->DumpToProto(&counterz);
std::string dump_buf;
if (absl::EndsWith(filename, ".json")) {
google::protobuf::util::JsonPrintOptions options;
options.preserve_proto_field_names = true;
google::protobuf::util::MessageToJsonString(counterz, &dump_buf, options);
} else {
counterz.SerializeToString(&dump_buf);
}
if (!WriteStringToFile(dump_buf, filename)) {
LOG(ERROR) << "failed to dump counterz stats to " << filename;
} else {
LOG(INFO) << "dumped counterz stats to " << filename;
}
}
/* static */
void Counterz::Quit() {
CHECK(instance_ != nullptr);
delete instance_;
instance_ = nullptr;
}
/* static */
Counterz* Counterz::Instance() {
return instance_;
}
} // namespace devtools_goma