Loading cmds/statsd/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ statsd_common_src := \ src/metrics/duration_helper/OringDurationTracker.cpp \ src/metrics/duration_helper/MaxDurationTracker.cpp \ src/metrics/ValueMetricProducer.cpp \ src/metrics/GaugeMetricProducer.cpp \ src/metrics/MetricsManager.cpp \ src/metrics/metrics_manager_util.cpp \ src/packages/UidMap.cpp \ Loading cmds/statsd/src/config/ConfigManager.cpp +16 −1 Original line number Diff line number Diff line Loading @@ -142,6 +142,9 @@ static StatsdConfig build_fake_config() { int KERNEL_WAKELOCK_TAG_ID = 1004; int KERNEL_WAKELOCK_NAME_KEY = 4; int DEVICE_TEMPERATURE_TAG_ID = 33; int DEVICE_TEMPERATURE_KEY = 1; // Count Screen ON events. CountMetric* metric = config.add_count_metric(); metric->set_metric_id(1); Loading Loading @@ -227,7 +230,7 @@ static StatsdConfig build_fake_config() { // Duration of screen on time. durationMetric = config.add_duration_metric(); durationMetric->set_metric_id(8); durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L); durationMetric->mutable_bucket()->set_bucket_size_millis(10 * 1000L); durationMetric->set_type(DurationMetric_AggregationType_DURATION_SUM); durationMetric->set_what("SCREEN_IS_ON"); Loading @@ -247,7 +250,19 @@ static StatsdConfig build_fake_config() { eventMetric->set_metric_id(9); eventMetric->set_what("SCREEN_TURNED_ON"); // Add an GaugeMetric. GaugeMetric* gaugeMetric = config.add_gauge_metric(); gaugeMetric->set_metric_id(10); gaugeMetric->set_what("DEVICE_TEMPERATURE"); gaugeMetric->set_gauge_field(DEVICE_TEMPERATURE_KEY); gaugeMetric->mutable_bucket()->set_bucket_size_millis(60 * 1000L); // Event matchers............ LogEntryMatcher* temperatureEntryMatcher = config.add_log_entry_matcher(); temperatureEntryMatcher->set_name("DEVICE_TEMPERATURE"); temperatureEntryMatcher->mutable_simple_log_entry_matcher()->set_tag( DEVICE_TEMPERATURE_TAG_ID); LogEntryMatcher* eventMatcher = config.add_log_entry_matcher(); eventMatcher->set_name("SCREEN_TURNED_ON"); SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher(); Loading cmds/statsd/src/metrics/GaugeMetricProducer.cpp 0 → 100644 +232 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * 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. */ #define DEBUG true // STOPSHIP if true #include "Log.h" #include "GaugeMetricProducer.h" #include "stats_util.h" #include <cutils/log.h> #include <limits.h> #include <stdlib.h> using std::map; using std::string; using std::unordered_map; using std::vector; namespace android { namespace os { namespace statsd { GaugeMetricProducer::GaugeMetricProducer(const GaugeMetric& metric, const int conditionIndex, const sp<ConditionWizard>& wizard, const int pullTagId) : MetricProducer((time(nullptr) * NANO_SECONDS_IN_A_SECOND), conditionIndex, wizard), mMetric(metric), mPullTagId(pullTagId) { if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) { mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000; } else { mBucketSizeNs = kDefaultGaugemBucketSizeNs; } // TODO: use UidMap if uid->pkg_name is required mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end()); if (metric.links().size() > 0) { mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(), metric.links().end()); mConditionSliced = true; } // Kicks off the puller immediately. if (mPullTagId != -1) { mStatsPullerManager.RegisterReceiver(mPullTagId, this, metric.bucket().bucket_size_millis()); } VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(), (long long)mBucketSizeNs, (long long)mStartTimeNs); } GaugeMetricProducer::~GaugeMetricProducer() { VLOG("~GaugeMetricProducer() called"); } void GaugeMetricProducer::finish() { } static void addSlicedGaugeToReport(const vector<KeyValuePair>& key, const vector<GaugeBucketInfo>& buckets, StatsLogReport_GaugeMetricDataWrapper& wrapper) { GaugeMetricData* data = wrapper.add_data(); for (const auto& kv : key) { data->add_dimension()->CopyFrom(kv); } for (const auto& bucket : buckets) { data->add_bucket_info()->CopyFrom(bucket); VLOG("\t bucket [%lld - %lld] gauge: %lld", bucket.start_bucket_nanos(), bucket.end_bucket_nanos(), bucket.gauge()); } } StatsLogReport GaugeMetricProducer::onDumpReport() { VLOG("gauge metric %lld dump report now...", mMetric.metric_id()); StatsLogReport report; report.set_metric_id(mMetric.metric_id()); report.set_start_report_nanos(mStartTimeNs); // Dump current bucket if it's stale. // If current bucket is still on-going, don't force dump current bucket. // In finish(), We can force dump current bucket. flushGaugeIfNeededLocked(time(nullptr) * NANO_SECONDS_IN_A_SECOND); report.set_end_report_nanos(mCurrentBucketStartTimeNs); StatsLogReport_GaugeMetricDataWrapper* wrapper = report.mutable_gauge_metrics(); for (const auto& pair : mPastBuckets) { const HashableDimensionKey& hashableKey = pair.first; auto it = mDimensionKeyMap.find(hashableKey); if (it == mDimensionKeyMap.end()) { ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str()); continue; } VLOG(" dimension key %s", hashableKey.c_str()); addSlicedGaugeToReport(it->second, pair.second, *wrapper); } return report; // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped. } void GaugeMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) { AutoMutex _l(mLock); VLOG("Metric %lld onConditionChanged", mMetric.metric_id()); mCondition = conditionMet; // Push mode. Nothing to do. if (mPullTagId == -1) { return; } // If (1) the condition is not met or (2) we already pulled the gauge metric in the current // bucket, do not pull gauge again. if (!mCondition || mCurrentSlicedBucket.size() > 0) { return; } vector<std::shared_ptr<LogEvent>> allData; if (!mStatsPullerManager.Pull(mPullTagId, &allData)) { ALOGE("Stats puller failed for tag: %d", mPullTagId); return; } for (const auto& data : allData) { onMatchedLogEvent(0, *data, false /*scheduledPull*/); } flushGaugeIfNeededLocked(eventTime); } void GaugeMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) { VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id()); } long GaugeMetricProducer::getGauge(const LogEvent& event) { status_t err = NO_ERROR; long val = event.GetLong(mMetric.gauge_field(), &err); if (err == NO_ERROR) { return val; } else { VLOG("Can't find value in message."); return -1; } } void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) { AutoMutex mutex(mLock); if (allData.size() == 0) { return; } for (const auto& data : allData) { onMatchedLogEvent(0, *data, true /*scheduledPull*/); } uint64_t eventTime = allData.at(0)->GetTimestampNs(); flushGaugeIfNeededLocked(eventTime); } void GaugeMetricProducer::onMatchedLogEventInternal( const size_t matcherIndex, const HashableDimensionKey& eventKey, const map<string, HashableDimensionKey>& conditionKey, bool condition, const LogEvent& event, bool scheduledPull) { if (condition == false) { return; } uint64_t eventTimeNs = event.GetTimestampNs(); if (eventTimeNs < mCurrentBucketStartTimeNs) { VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs, (long long)mCurrentBucketStartTimeNs); return; } // For gauge metric, we just simply use the latest guage in the given bucket. const long gauge = getGauge(event); if (gauge < 0) { VLOG("Invalid gauge at event Time: %lld", (long long)eventTimeNs); return; } mCurrentSlicedBucket[eventKey] = gauge; if (mPullTagId < 0) { flushGaugeIfNeededLocked(eventTimeNs); } } // When a new matched event comes in, we check if event falls into the current // bucket. If not, flush the old counter to past buckets and initialize the new // bucket. // if data is pushed, onMatchedLogEvent will only be called through onConditionChanged() inside // the GaugeMetricProducer while holding the lock. void GaugeMetricProducer::flushGaugeIfNeededLocked(const uint64_t eventTimeNs) { if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) { VLOG("event time is %lld, less than next bucket start time %lld", (long long)eventTimeNs, (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs)); return; } // Adjusts the bucket start time int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs; GaugeBucketInfo info; info.set_start_bucket_nanos(mCurrentBucketStartTimeNs); info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs); for (const auto& slice : mCurrentSlicedBucket) { info.set_gauge(slice.second); auto& bucketList = mPastBuckets[slice.first]; bucketList.push_back(info); VLOG("gauge metric %lld, dump key value: %s -> %ld", mMetric.metric_id(), slice.first.c_str(), slice.second); } // Reset counters mCurrentSlicedBucket.clear(); mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs; VLOG("metric %lld: new bucket start time: %lld", mMetric.metric_id(), (long long)mCurrentBucketStartTimeNs); } } // namespace statsd } // namespace os } // namespace android cmds/statsd/src/metrics/GaugeMetricProducer.h 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * 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. */ #pragma once #include <unordered_map> #include "../condition/ConditionTracker.h" #include "../external/PullDataReceiver.h" #include "../external/StatsPullerManager.h" #include "../matchers/matcher_util.h" #include "MetricProducer.h" #include "frameworks/base/cmds/statsd/src/stats_log.pb.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "stats_util.h" namespace android { namespace os { namespace statsd { // This gauge metric producer first register the puller to automatically pull the gauge at the // beginning of each bucket. If the condition is met, insert it to the bucket info. Otherwise // proactively pull the gauge when the condition is changed to be true. Therefore, the gauge metric // producer always reports the guage at the earliest time of the bucket when the condition is met. class GaugeMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver { public: // TODO: Pass in the start time from MetricsManager, it should be consistent // for all metrics. GaugeMetricProducer(const GaugeMetric& countMetric, const int conditionIndex, const sp<ConditionWizard>& wizard, const int pullTagId); virtual ~GaugeMetricProducer(); // Handles when the pulled data arrives. void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override; void onConditionChanged(const bool conditionMet, const uint64_t eventTime) override; void onSlicedConditionMayChange(const uint64_t eventTime) override; void finish() override; StatsLogReport onDumpReport() override; // TODO: implements it when supporting proto stream. size_t byteSize() override { return 0; }; // TODO: Implement this later. virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{}; // TODO: Implement this later. virtual void notifyAppRemoved(const string& apk, const int uid) override{}; protected: void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey, const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition, const LogEvent& event, bool scheduledPull) override; private: // The default bucket size for gauge metric is 1 second. static const uint64_t kDefaultGaugemBucketSizeNs = 1000 * 1000 * 1000; const GaugeMetric mMetric; StatsPullerManager& mStatsPullerManager = StatsPullerManager::GetInstance(); // tagId for pulled data. -1 if this is not pulled const int mPullTagId; Mutex mLock; // Save the past buckets and we can clear when the StatsLogReport is dumped. std::unordered_map<HashableDimensionKey, std::vector<GaugeBucketInfo>> mPastBuckets; // The current bucket. std::unordered_map<HashableDimensionKey, long> mCurrentSlicedBucket; void flushGaugeIfNeededLocked(const uint64_t newEventTime); long getGauge(const LogEvent& event); }; } // namespace statsd } // namespace os } // namespace android cmds/statsd/src/metrics/MetricsManager.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -146,7 +146,8 @@ void MetricsManager::onLogEvent(const LogEvent& event) { auto& metricList = pair->second; for (const int metricIndex : metricList) { // pushed metrics are never scheduled pulls mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, event, false); mAllMetricProducers[metricIndex]->onMatchedLogEvent( i, event, false /* schedulePull */); } } } Loading Loading
cmds/statsd/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ statsd_common_src := \ src/metrics/duration_helper/OringDurationTracker.cpp \ src/metrics/duration_helper/MaxDurationTracker.cpp \ src/metrics/ValueMetricProducer.cpp \ src/metrics/GaugeMetricProducer.cpp \ src/metrics/MetricsManager.cpp \ src/metrics/metrics_manager_util.cpp \ src/packages/UidMap.cpp \ Loading
cmds/statsd/src/config/ConfigManager.cpp +16 −1 Original line number Diff line number Diff line Loading @@ -142,6 +142,9 @@ static StatsdConfig build_fake_config() { int KERNEL_WAKELOCK_TAG_ID = 1004; int KERNEL_WAKELOCK_NAME_KEY = 4; int DEVICE_TEMPERATURE_TAG_ID = 33; int DEVICE_TEMPERATURE_KEY = 1; // Count Screen ON events. CountMetric* metric = config.add_count_metric(); metric->set_metric_id(1); Loading Loading @@ -227,7 +230,7 @@ static StatsdConfig build_fake_config() { // Duration of screen on time. durationMetric = config.add_duration_metric(); durationMetric->set_metric_id(8); durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L); durationMetric->mutable_bucket()->set_bucket_size_millis(10 * 1000L); durationMetric->set_type(DurationMetric_AggregationType_DURATION_SUM); durationMetric->set_what("SCREEN_IS_ON"); Loading @@ -247,7 +250,19 @@ static StatsdConfig build_fake_config() { eventMetric->set_metric_id(9); eventMetric->set_what("SCREEN_TURNED_ON"); // Add an GaugeMetric. GaugeMetric* gaugeMetric = config.add_gauge_metric(); gaugeMetric->set_metric_id(10); gaugeMetric->set_what("DEVICE_TEMPERATURE"); gaugeMetric->set_gauge_field(DEVICE_TEMPERATURE_KEY); gaugeMetric->mutable_bucket()->set_bucket_size_millis(60 * 1000L); // Event matchers............ LogEntryMatcher* temperatureEntryMatcher = config.add_log_entry_matcher(); temperatureEntryMatcher->set_name("DEVICE_TEMPERATURE"); temperatureEntryMatcher->mutable_simple_log_entry_matcher()->set_tag( DEVICE_TEMPERATURE_TAG_ID); LogEntryMatcher* eventMatcher = config.add_log_entry_matcher(); eventMatcher->set_name("SCREEN_TURNED_ON"); SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher(); Loading
cmds/statsd/src/metrics/GaugeMetricProducer.cpp 0 → 100644 +232 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * 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. */ #define DEBUG true // STOPSHIP if true #include "Log.h" #include "GaugeMetricProducer.h" #include "stats_util.h" #include <cutils/log.h> #include <limits.h> #include <stdlib.h> using std::map; using std::string; using std::unordered_map; using std::vector; namespace android { namespace os { namespace statsd { GaugeMetricProducer::GaugeMetricProducer(const GaugeMetric& metric, const int conditionIndex, const sp<ConditionWizard>& wizard, const int pullTagId) : MetricProducer((time(nullptr) * NANO_SECONDS_IN_A_SECOND), conditionIndex, wizard), mMetric(metric), mPullTagId(pullTagId) { if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) { mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000; } else { mBucketSizeNs = kDefaultGaugemBucketSizeNs; } // TODO: use UidMap if uid->pkg_name is required mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end()); if (metric.links().size() > 0) { mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(), metric.links().end()); mConditionSliced = true; } // Kicks off the puller immediately. if (mPullTagId != -1) { mStatsPullerManager.RegisterReceiver(mPullTagId, this, metric.bucket().bucket_size_millis()); } VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(), (long long)mBucketSizeNs, (long long)mStartTimeNs); } GaugeMetricProducer::~GaugeMetricProducer() { VLOG("~GaugeMetricProducer() called"); } void GaugeMetricProducer::finish() { } static void addSlicedGaugeToReport(const vector<KeyValuePair>& key, const vector<GaugeBucketInfo>& buckets, StatsLogReport_GaugeMetricDataWrapper& wrapper) { GaugeMetricData* data = wrapper.add_data(); for (const auto& kv : key) { data->add_dimension()->CopyFrom(kv); } for (const auto& bucket : buckets) { data->add_bucket_info()->CopyFrom(bucket); VLOG("\t bucket [%lld - %lld] gauge: %lld", bucket.start_bucket_nanos(), bucket.end_bucket_nanos(), bucket.gauge()); } } StatsLogReport GaugeMetricProducer::onDumpReport() { VLOG("gauge metric %lld dump report now...", mMetric.metric_id()); StatsLogReport report; report.set_metric_id(mMetric.metric_id()); report.set_start_report_nanos(mStartTimeNs); // Dump current bucket if it's stale. // If current bucket is still on-going, don't force dump current bucket. // In finish(), We can force dump current bucket. flushGaugeIfNeededLocked(time(nullptr) * NANO_SECONDS_IN_A_SECOND); report.set_end_report_nanos(mCurrentBucketStartTimeNs); StatsLogReport_GaugeMetricDataWrapper* wrapper = report.mutable_gauge_metrics(); for (const auto& pair : mPastBuckets) { const HashableDimensionKey& hashableKey = pair.first; auto it = mDimensionKeyMap.find(hashableKey); if (it == mDimensionKeyMap.end()) { ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str()); continue; } VLOG(" dimension key %s", hashableKey.c_str()); addSlicedGaugeToReport(it->second, pair.second, *wrapper); } return report; // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped. } void GaugeMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) { AutoMutex _l(mLock); VLOG("Metric %lld onConditionChanged", mMetric.metric_id()); mCondition = conditionMet; // Push mode. Nothing to do. if (mPullTagId == -1) { return; } // If (1) the condition is not met or (2) we already pulled the gauge metric in the current // bucket, do not pull gauge again. if (!mCondition || mCurrentSlicedBucket.size() > 0) { return; } vector<std::shared_ptr<LogEvent>> allData; if (!mStatsPullerManager.Pull(mPullTagId, &allData)) { ALOGE("Stats puller failed for tag: %d", mPullTagId); return; } for (const auto& data : allData) { onMatchedLogEvent(0, *data, false /*scheduledPull*/); } flushGaugeIfNeededLocked(eventTime); } void GaugeMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) { VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id()); } long GaugeMetricProducer::getGauge(const LogEvent& event) { status_t err = NO_ERROR; long val = event.GetLong(mMetric.gauge_field(), &err); if (err == NO_ERROR) { return val; } else { VLOG("Can't find value in message."); return -1; } } void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) { AutoMutex mutex(mLock); if (allData.size() == 0) { return; } for (const auto& data : allData) { onMatchedLogEvent(0, *data, true /*scheduledPull*/); } uint64_t eventTime = allData.at(0)->GetTimestampNs(); flushGaugeIfNeededLocked(eventTime); } void GaugeMetricProducer::onMatchedLogEventInternal( const size_t matcherIndex, const HashableDimensionKey& eventKey, const map<string, HashableDimensionKey>& conditionKey, bool condition, const LogEvent& event, bool scheduledPull) { if (condition == false) { return; } uint64_t eventTimeNs = event.GetTimestampNs(); if (eventTimeNs < mCurrentBucketStartTimeNs) { VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs, (long long)mCurrentBucketStartTimeNs); return; } // For gauge metric, we just simply use the latest guage in the given bucket. const long gauge = getGauge(event); if (gauge < 0) { VLOG("Invalid gauge at event Time: %lld", (long long)eventTimeNs); return; } mCurrentSlicedBucket[eventKey] = gauge; if (mPullTagId < 0) { flushGaugeIfNeededLocked(eventTimeNs); } } // When a new matched event comes in, we check if event falls into the current // bucket. If not, flush the old counter to past buckets and initialize the new // bucket. // if data is pushed, onMatchedLogEvent will only be called through onConditionChanged() inside // the GaugeMetricProducer while holding the lock. void GaugeMetricProducer::flushGaugeIfNeededLocked(const uint64_t eventTimeNs) { if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) { VLOG("event time is %lld, less than next bucket start time %lld", (long long)eventTimeNs, (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs)); return; } // Adjusts the bucket start time int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs; GaugeBucketInfo info; info.set_start_bucket_nanos(mCurrentBucketStartTimeNs); info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs); for (const auto& slice : mCurrentSlicedBucket) { info.set_gauge(slice.second); auto& bucketList = mPastBuckets[slice.first]; bucketList.push_back(info); VLOG("gauge metric %lld, dump key value: %s -> %ld", mMetric.metric_id(), slice.first.c_str(), slice.second); } // Reset counters mCurrentSlicedBucket.clear(); mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs; VLOG("metric %lld: new bucket start time: %lld", mMetric.metric_id(), (long long)mCurrentBucketStartTimeNs); } } // namespace statsd } // namespace os } // namespace android
cmds/statsd/src/metrics/GaugeMetricProducer.h 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * 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. */ #pragma once #include <unordered_map> #include "../condition/ConditionTracker.h" #include "../external/PullDataReceiver.h" #include "../external/StatsPullerManager.h" #include "../matchers/matcher_util.h" #include "MetricProducer.h" #include "frameworks/base/cmds/statsd/src/stats_log.pb.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "stats_util.h" namespace android { namespace os { namespace statsd { // This gauge metric producer first register the puller to automatically pull the gauge at the // beginning of each bucket. If the condition is met, insert it to the bucket info. Otherwise // proactively pull the gauge when the condition is changed to be true. Therefore, the gauge metric // producer always reports the guage at the earliest time of the bucket when the condition is met. class GaugeMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver { public: // TODO: Pass in the start time from MetricsManager, it should be consistent // for all metrics. GaugeMetricProducer(const GaugeMetric& countMetric, const int conditionIndex, const sp<ConditionWizard>& wizard, const int pullTagId); virtual ~GaugeMetricProducer(); // Handles when the pulled data arrives. void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override; void onConditionChanged(const bool conditionMet, const uint64_t eventTime) override; void onSlicedConditionMayChange(const uint64_t eventTime) override; void finish() override; StatsLogReport onDumpReport() override; // TODO: implements it when supporting proto stream. size_t byteSize() override { return 0; }; // TODO: Implement this later. virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{}; // TODO: Implement this later. virtual void notifyAppRemoved(const string& apk, const int uid) override{}; protected: void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey, const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition, const LogEvent& event, bool scheduledPull) override; private: // The default bucket size for gauge metric is 1 second. static const uint64_t kDefaultGaugemBucketSizeNs = 1000 * 1000 * 1000; const GaugeMetric mMetric; StatsPullerManager& mStatsPullerManager = StatsPullerManager::GetInstance(); // tagId for pulled data. -1 if this is not pulled const int mPullTagId; Mutex mLock; // Save the past buckets and we can clear when the StatsLogReport is dumped. std::unordered_map<HashableDimensionKey, std::vector<GaugeBucketInfo>> mPastBuckets; // The current bucket. std::unordered_map<HashableDimensionKey, long> mCurrentSlicedBucket; void flushGaugeIfNeededLocked(const uint64_t newEventTime); long getGauge(const LogEvent& event); }; } // namespace statsd } // namespace os } // namespace android
cmds/statsd/src/metrics/MetricsManager.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -146,7 +146,8 @@ void MetricsManager::onLogEvent(const LogEvent& event) { auto& metricList = pair->second; for (const int metricIndex : metricList) { // pushed metrics are never scheduled pulls mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, event, false); mAllMetricProducers[metricIndex]->onMatchedLogEvent( i, event, false /* schedulePull */); } } } Loading