Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ccd84c03 authored by Ken Mixter's avatar Ken Mixter
Browse files

Add # daily crashes metrics and separate kernel crashes out.

parent 3fd74748
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -183,4 +183,32 @@ void TaggedCounter::WriteRecord(int fd) {
  }
}

FrequencyCounter::FrequencyCounter() : cycle_duration_(1) {
}

FrequencyCounter::~FrequencyCounter() {
}

void FrequencyCounter::Init(const char* filename,
                            TaggedCounterInterface::Reporter reporter,
                            void* reporter_handle,
                            time_t cycle_duration) {
  // Allow tests to inject tagged_counter_ dependency.
  if (tagged_counter_.get() == NULL) {
    tagged_counter_.reset(new TaggedCounter());
  }
  tagged_counter_->Init(filename, reporter, reporter_handle);
  DCHECK(cycle_duration > 0);
  cycle_duration_ = cycle_duration;
}

void FrequencyCounter::UpdateInternal(int32 count, time_t now) {
  DCHECK(tagged_counter_.get() != NULL);
  tagged_counter_->Update(GetCycleNumber(now), count);
}

int32 FrequencyCounter::GetCycleNumber(time_t now) {
  return now / cycle_duration_;
}

}  // namespace chromeos_metrics
+46 −0
Original line number Diff line number Diff line
@@ -5,11 +5,18 @@
#ifndef METRICS_COUNTER_H_
#define METRICS_COUNTER_H_

#include <time.h>

#include <base/basictypes.h>
#include <base/scoped_ptr.h>
#include <gtest/gtest_prod.h>  // for FRIEND_TEST

namespace chromeos_metrics {

// Constants useful for frequency statistics.
const int kSecondsPerDay = 60 * 60 * 24;
const int kSecondsPerWeek = kSecondsPerDay * 7;

// TaggedCounter maintains a persistent storage (i.e., a file)
// aggregation counter for a given tag (e.g., day, hour) that survives
// system shutdowns, reboots and crashes, as well as daemon process
@@ -152,6 +159,45 @@ class TaggedCounter : public TaggedCounterInterface {
  RecordState record_state_;
};

// FrequencyCounter uses TaggedCounter to maintain a persistent
// storage of the number of events that occur in a given cycle
// duration (in other words, a frequency count).  For example, to
// count the number of blips per day, initialize |cycle_duration| to
// chromeos_metrics::kSecondsPerDay, and call Update with the number
// of blips that happen concurrently (usually 1).  Reporting of the
// value is done through TaggedCounter's reporter function.
class FrequencyCounter {
 public:
  // Create a new frequency counter.
  FrequencyCounter();
  virtual ~FrequencyCounter();

  // Initialize a frequency counter, which is necessary before first use.
  // |filename|, |reporter|, and |reporter_handle| are used as in
  // TaggedCounter::Init.  |cycle_duration| is the number of seconds
  // in a cycle.
  virtual void Init(const char* filename,
                    TaggedCounterInterface::Reporter reporter,
                    void* reporter_handle,
                    time_t cycle_duration);
  // Record that an event occurred.  |count| is the number of concurrent
  // events that have occurred.  The time is implicitly assumed to be the
  // time of the call.
  virtual void Update(int32 count) {
    UpdateInternal(count, time(NULL));
  }

 private:
  friend class FrequencyCounterTest;
  FRIEND_TEST(FrequencyCounterTest, UpdateInternal);

  void UpdateInternal(int32 count, time_t now);
  int32 GetCycleNumber(time_t now);

  time_t cycle_duration_;
  scoped_ptr<TaggedCounterInterface> tagged_counter_;
};

}  // namespace chromeos_metrics

#endif  // METRICS_COUNTER_H_
+9 −1
Original line number Diff line number Diff line
@@ -21,7 +21,15 @@ class TaggedCounterMock : public TaggedCounterInterface {
  MOCK_METHOD0(Flush, void());
};

class FrequencyCounterMock : public FrequencyCounter {
 public:
  MOCK_METHOD4(Init, void(const char* filename,
                          TaggedCounterInterface::Reporter reporter,
                          void* reporter_handle,
                          time_t cycle_duration));
  MOCK_METHOD1(Update, void(int32 count));
};

}  // namespace chromeos_metrics

#endif  // METRICS_COUNTER_MOCK_H_
+59 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <gtest/gtest.h>

#include "counter.h"
#include "counter_mock.h"  // For TaggedCounterMock.

using ::testing::_;
using ::testing::MockFunction;
@@ -255,6 +256,64 @@ TEST_F(TaggedCounterTest, Update) {
  EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
}

class FrequencyCounterTest : public testing::Test {
 protected:
  virtual void SetUp() {
    tagged_counter_ = new StrictMock<TaggedCounterMock>;
    frequency_counter_.tagged_counter_.reset(tagged_counter_);
  }

  static void FakeReporter(void *, int32, int32) {
  }

  void CheckInit(int32 cycle_duration);
  void CheckCycleNumber(int32 cycle_duration);

  FrequencyCounter frequency_counter_;
  StrictMock<TaggedCounterMock>* tagged_counter_;

  TaggedCounter::Reporter reporter_;
};

void FrequencyCounterTest::CheckInit(int32 cycle_duration) {
  EXPECT_CALL(*tagged_counter_, Init(kTestRecordFile, FakeReporter, this))
      .Times(1)
      .RetiresOnSaturation();
  frequency_counter_.Init(kTestRecordFile,
                          FakeReporter,
                          this,
                          cycle_duration);
  EXPECT_EQ(cycle_duration, frequency_counter_.cycle_duration_);
}

TEST_F(FrequencyCounterTest, Init) {
  CheckInit(100);
}

void FrequencyCounterTest::CheckCycleNumber(int32 cycle_duration) {
  CheckInit(cycle_duration);
  EXPECT_EQ(150, frequency_counter_.GetCycleNumber(cycle_duration * 150));
  EXPECT_EQ(150, frequency_counter_.GetCycleNumber(cycle_duration * 150 +
                                                   cycle_duration - 1));
  EXPECT_EQ(151, frequency_counter_.GetCycleNumber(cycle_duration * 151 + 1));
  EXPECT_EQ(0, frequency_counter_.GetCycleNumber(0));
}


TEST_F(FrequencyCounterTest, GetCycleNumberForWeek) {
  CheckCycleNumber(kSecondsPerWeek);
}

TEST_F(FrequencyCounterTest, GetCycleNumberForDay) {
  CheckCycleNumber(kSecondsPerDay);
}

TEST_F(FrequencyCounterTest, UpdateInternal) {
  CheckInit(kSecondsPerWeek);
  EXPECT_CALL(*tagged_counter_, Update(150, 2));
  frequency_counter_.UpdateInternal(2, kSecondsPerWeek * 150);
}

}  // namespace chromeos_metrics

int main(int argc, char** argv) {
+153 −30
Original line number Diff line number Diff line
@@ -39,6 +39,10 @@ static const int kSecondsPerWeek = kSecondsPerDay * kDaysPerWeek;
static const int kUseMonitorIntervalInit = 1 * kSecondsPerMinute;
static const int kUseMonitorIntervalMax = 10 * kSecondsPerMinute;

const char kKernelCrashDetectedFile[] = "/tmp/kernel-crash-detected";
static const char kUncleanShutdownDetectedFile[] =
      "/tmp/unclean-shutdown-detected";

// static metrics parameters.
const char MetricsDaemon::kMetricDailyUseTimeName[] =
    "Logging.DailyUseTime";
@@ -46,12 +50,6 @@ const int MetricsDaemon::kMetricDailyUseTimeMin = 1;
const int MetricsDaemon::kMetricDailyUseTimeMax = kMinutesPerDay;
const int MetricsDaemon::kMetricDailyUseTimeBuckets = 50;

const char MetricsDaemon::kMetricKernelCrashIntervalName[] =
    "Logging.KernelCrashInterval";
const int MetricsDaemon::kMetricKernelCrashIntervalMin = 1;
const int MetricsDaemon::kMetricKernelCrashIntervalMax = 4 * kSecondsPerWeek;
const int MetricsDaemon::kMetricKernelCrashIntervalBuckets = 50;

const char MetricsDaemon::kMetricTimeToNetworkDropName[] =
    "Network.TimeToDrop";
const int MetricsDaemon::kMetricTimeToNetworkDropMin = 1;
@@ -59,11 +57,33 @@ const int MetricsDaemon::kMetricTimeToNetworkDropMax =
    8 /* hours */ * kMinutesPerHour * kSecondsPerMinute;
const int MetricsDaemon::kMetricTimeToNetworkDropBuckets = 50;

// crash interval metrics
const char MetricsDaemon::kMetricKernelCrashIntervalName[] =
    "Logging.KernelCrashInterval";
const char MetricsDaemon::kMetricUncleanShutdownIntervalName[] =
    "Logging.UncleanShutdownInterval";
const char MetricsDaemon::kMetricUserCrashIntervalName[] =
    "Logging.UserCrashInterval";
const int MetricsDaemon::kMetricUserCrashIntervalMin = 1;
const int MetricsDaemon::kMetricUserCrashIntervalMax = 4 * kSecondsPerWeek;
const int MetricsDaemon::kMetricUserCrashIntervalBuckets = 50;

const int MetricsDaemon::kMetricCrashIntervalMin = 1;
const int MetricsDaemon::kMetricCrashIntervalMax =
    4 * kSecondsPerWeek;
const int MetricsDaemon::kMetricCrashIntervalBuckets = 50;

// crash frequency metrics
const char MetricsDaemon::kMetricAnyCrashesDailyName[] =
    "Logging.AnyCrashesDaily";
const char MetricsDaemon::kMetricKernelCrashesDailyName[] =
    "Logging.KernelCrashesDaily";
const char MetricsDaemon::kMetricUncleanShutdownsDailyName[] =
    "Logging.UncleanShutdownsDaily";
const char MetricsDaemon::kMetricUserCrashesDailyName[] =
    "Logging.UserCrashesDaily";
const char MetricsDaemon::kMetricCrashesDailyMin = 1;
const char MetricsDaemon::kMetricCrashesDailyMax = 100;
const char MetricsDaemon::kMetricCrashesDailyBuckets = 50;



// static
const char* MetricsDaemon::kDBusMatches_[] = {
@@ -168,8 +188,14 @@ void MetricsDaemon::Run(bool run_as_daemon) {
  if (run_as_daemon && daemon(0, 0) != 0)
    return;

  static const char kKernelCrashDetectedFile[] = "/tmp/kernel-crash-detected";
  CheckKernelCrash(kKernelCrashDetectedFile);
  if (CheckSystemCrash(kKernelCrashDetectedFile)) {
    ProcessKernelCrash();
  }

  if (CheckSystemCrash(kUncleanShutdownDetectedFile)) {
    ProcessUncleanShutdown();
  }

  Loop();
}

@@ -180,19 +206,57 @@ void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) {

  static const char kDailyUseRecordFile[] = "/var/log/metrics/daily-usage";
  daily_use_.reset(new chromeos_metrics::TaggedCounter());
  daily_use_->Init(kDailyUseRecordFile, &DailyUseReporter, this);
  daily_use_->Init(kDailyUseRecordFile, &ReportDailyUse, this);

  static const char kUserCrashIntervalRecordFile[] =
      "/var/log/metrics/user-crash-interval";
  user_crash_interval_.reset(new chromeos_metrics::TaggedCounter());
  user_crash_interval_->Init(kUserCrashIntervalRecordFile,
                             &UserCrashIntervalReporter, this);
                             &ReportUserCrashInterval, this);

  static const char kKernelCrashIntervalRecordFile[] =
      "/var/log/metrics/kernel-crash-interval";
  kernel_crash_interval_.reset(new chromeos_metrics::TaggedCounter());
  kernel_crash_interval_->Init(kKernelCrashIntervalRecordFile,
                               &KernelCrashIntervalReporter, this);
                               &ReportKernelCrashInterval, this);

  static const char kUncleanShutdownDetectedFile[] =
      "/var/log/metrics/unclean-shutdown-interval";
  unclean_shutdown_interval_.reset(new chromeos_metrics::TaggedCounter());
  unclean_shutdown_interval_->Init(kUncleanShutdownDetectedFile,
                                   &ReportUncleanShutdownInterval, this);

  static const char kUserCrashesDailyRecordFile[] =
      "/var/log/metrics/user-crashes-daily";
  user_crashes_daily_.reset(new chromeos_metrics::FrequencyCounter());
  user_crashes_daily_->Init(kUserCrashesDailyRecordFile,
                            &ReportUserCrashesDaily,
                            this,
                            chromeos_metrics::kSecondsPerDay);

  static const char kKernelCrashesDailyRecordFile[] =
      "/var/log/metrics/kernel-crashes-daily";
  kernel_crashes_daily_.reset(new chromeos_metrics::FrequencyCounter());
  kernel_crashes_daily_->Init(kKernelCrashesDailyRecordFile,
                              &ReportKernelCrashesDaily,
                              this,
                              chromeos_metrics::kSecondsPerDay);

  static const char kUncleanShutdownsDailyRecordFile[] =
      "/var/log/metrics/unclean-shutdowns-daily";
  unclean_shutdowns_daily_.reset(new chromeos_metrics::FrequencyCounter());
  unclean_shutdowns_daily_->Init(kUncleanShutdownsDailyRecordFile,
                                 &ReportUncleanShutdownsDaily,
                                 this,
                                 chromeos_metrics::kSecondsPerDay);

  static const char kAnyCrashesUserCrashDailyRecordFile[] =
      "/var/log/metrics/any-crashes-daily";
  any_crashes_daily_.reset(new chromeos_metrics::FrequencyCounter());
  any_crashes_daily_->Init(kAnyCrashesUserCrashDailyRecordFile,
                           &ReportAnyCrashesDaily,
                           this,
                           chromeos_metrics::kSecondsPerDay);

  // Don't setup D-Bus and GLib in test mode.
  if (testing)
@@ -408,6 +472,9 @@ void MetricsDaemon::ProcessUserCrash() {

  // Reports the active use time since the last crash and resets it.
  user_crash_interval_->Flush();

  user_crashes_daily_->Update(1);
  any_crashes_daily_->Update(1);
}

void MetricsDaemon::ProcessKernelCrash() {
@@ -416,19 +483,32 @@ void MetricsDaemon::ProcessKernelCrash() {

  // Reports the active use time since the last crash and resets it.
  kernel_crash_interval_->Flush();

  kernel_crashes_daily_->Update(1);
  any_crashes_daily_->Update(1);
}

void MetricsDaemon::ProcessUncleanShutdown() {
  // Counts the active use time up to now.
  SetUserActiveState(user_active_, Time::Now());

  // Reports the active use time since the last crash and resets it.
  unclean_shutdown_interval_->Flush();

  unclean_shutdowns_daily_->Update(1);
  any_crashes_daily_->Update(1);
}

void MetricsDaemon::CheckKernelCrash(const std::string& crash_file) {
bool MetricsDaemon::CheckSystemCrash(const std::string& crash_file) {
  FilePath crash_detected(crash_file);
  if (!file_util::PathExists(crash_detected))
    return;

  ProcessKernelCrash();
    return false;

  // Deletes the crash-detected file so that the daemon doesn't report
  // another kernel crash in case it's restarted.
  file_util::Delete(crash_detected,
                    false);  // recursive
  return true;
}

// static
@@ -492,7 +572,7 @@ void MetricsDaemon::UnscheduleUseMonitor() {
}

// static
void MetricsDaemon::DailyUseReporter(void* handle, int tag, int count) {
void MetricsDaemon::ReportDailyUse(void* handle, int tag, int count) {
  if (count <= 0)
    return;

@@ -505,25 +585,68 @@ void MetricsDaemon::DailyUseReporter(void* handle, int tag, int count) {
}

// static
void MetricsDaemon::UserCrashIntervalReporter(void* handle,
                                              int tag, int count) {
void MetricsDaemon::ReportCrashInterval(const char* histogram_name,
                                        void* handle, int count) {
  MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle);
  daemon->SendMetric(kMetricUserCrashIntervalName, count,
                     kMetricUserCrashIntervalMin,
                     kMetricUserCrashIntervalMax,
                     kMetricUserCrashIntervalBuckets);
  daemon->SendMetric(histogram_name, count,
                     kMetricCrashIntervalMin,
                     kMetricCrashIntervalMax,
                     kMetricCrashIntervalBuckets);
}

// static
void MetricsDaemon::ReportUserCrashInterval(void* handle,
                                            int tag, int count) {
  ReportCrashInterval(kMetricUserCrashIntervalName, handle, count);
}

// static
void MetricsDaemon::ReportKernelCrashInterval(void* handle,
                                                int tag, int count) {
  ReportCrashInterval(kMetricKernelCrashIntervalName, handle, count);
}

// static
void MetricsDaemon::KernelCrashIntervalReporter(void* handle,
void MetricsDaemon::ReportUncleanShutdownInterval(void* handle,
                                                    int tag, int count) {
  ReportCrashInterval(kMetricUncleanShutdownIntervalName, handle, count);
}

// static
void MetricsDaemon::ReportCrashesDailyFrequency(const char* histogram_name,
                                                void* handle,
                                                int count) {
  MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle);
  daemon->SendMetric(kMetricKernelCrashIntervalName, count,
                     kMetricKernelCrashIntervalMin,
                     kMetricKernelCrashIntervalMax,
                     kMetricKernelCrashIntervalBuckets);
  daemon->SendMetric(histogram_name, count,
                     kMetricCrashesDailyMin,
                     kMetricCrashesDailyMax,
                     kMetricCrashesDailyBuckets);
}

// static
void MetricsDaemon::ReportUserCrashesDaily(void* handle,
                                           int tag, int count) {
  ReportCrashesDailyFrequency(kMetricUserCrashesDailyName, handle, count);
}

// static
void MetricsDaemon::ReportKernelCrashesDaily(void* handle,
                                             int tag, int count) {
  ReportCrashesDailyFrequency(kMetricKernelCrashesDailyName, handle, count);
}

// static
void MetricsDaemon::ReportUncleanShutdownsDaily(void* handle,
                                                int tag, int count) {
  ReportCrashesDailyFrequency(kMetricUncleanShutdownsDailyName, handle, count);
}

// static
void MetricsDaemon::ReportAnyCrashesDaily(void* handle, int tag, int count) {
  ReportCrashesDailyFrequency(kMetricAnyCrashesDailyName, handle, count);
}


void MetricsDaemon::SendMetric(const string& name, int sample,
                               int min, int max, int nbuckets) {
  DLOG(INFO) << "received metric: " << name << " " << sample << " "
Loading