Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Tej Singh | 484524a | 2018-02-01 15:10:05 -0800 | [diff] [blame] | 17 | #define DEBUG false // STOPSHIP if true |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame] | 18 | #include "Log.h" |
| 19 | |
| 20 | #include "DurationAnomalyTracker.h" |
| 21 | #include "guardrail/StatsdStats.h" |
| 22 | |
| 23 | namespace android { |
| 24 | namespace os { |
| 25 | namespace statsd { |
| 26 | |
Yangster-mac | 932ecec | 2018-02-01 10:23:52 -0800 | [diff] [blame] | 27 | DurationAnomalyTracker::DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey, |
| 28 | const sp<AlarmMonitor>& alarmMonitor) |
Bookatz | 6a1d3af | 2018-03-16 15:25:49 -0700 | [diff] [blame] | 29 | : AnomalyTracker(alert, configKey), mAlarmMonitor(alarmMonitor) { |
| 30 | VLOG("DurationAnomalyTracker() called"); |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame] | 31 | } |
| 32 | |
| 33 | DurationAnomalyTracker::~DurationAnomalyTracker() { |
Bookatz | 6a1d3af | 2018-03-16 15:25:49 -0700 | [diff] [blame] | 34 | VLOG("~DurationAnomalyTracker() called"); |
Bookatz | 3e8cd35 | 2018-03-16 10:09:59 -0700 | [diff] [blame] | 35 | cancelAllAlarms(); |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame] | 36 | } |
| 37 | |
Yangster-mac | 9369446 | 2018-01-22 20:49:31 -0800 | [diff] [blame] | 38 | void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey, |
Yangster-mac | b142cc8 | 2018-03-30 15:22:08 -0700 | [diff] [blame] | 39 | const int64_t& timestampNs) { |
Bookatz | 66fe061 | 2018-02-07 18:51:48 -0800 | [diff] [blame] | 40 | // Alarms are stored in secs. Must round up, since if it fires early, it is ignored completely. |
Yangster-mac | be10ddf | 2018-03-13 15:39:51 -0700 | [diff] [blame] | 41 | uint32_t timestampSec = static_cast<uint32_t>((timestampNs -1) / NS_PER_SEC) + 1; // round up |
Bookatz | 1bf9438 | 2018-01-04 11:43:20 -0800 | [diff] [blame] | 42 | if (isInRefractoryPeriod(timestampNs, dimensionKey)) { |
Yangster-mac | be10ddf | 2018-03-13 15:39:51 -0700 | [diff] [blame] | 43 | VLOG("Not setting anomaly alarm since it would fall in the refractory period."); |
| 44 | return; |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame] | 45 | } |
Bookatz | 6bf9825 | 2018-03-14 10:44:24 -0700 | [diff] [blame] | 46 | |
| 47 | auto itr = mAlarms.find(dimensionKey); |
| 48 | if (itr != mAlarms.end() && mAlarmMonitor != nullptr) { |
| 49 | mAlarmMonitor->remove(itr->second); |
| 50 | } |
| 51 | |
Yangster-mac | 932ecec | 2018-02-01 10:23:52 -0800 | [diff] [blame] | 52 | sp<const InternalAlarm> alarm = new InternalAlarm{timestampSec}; |
Bookatz | 6bf9825 | 2018-03-14 10:44:24 -0700 | [diff] [blame] | 53 | mAlarms[dimensionKey] = alarm; |
Yangster-mac | 932ecec | 2018-02-01 10:23:52 -0800 | [diff] [blame] | 54 | if (mAlarmMonitor != nullptr) { |
| 55 | mAlarmMonitor->add(alarm); |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame] | 56 | } |
| 57 | } |
| 58 | |
Bookatz | 3e8cd35 | 2018-03-16 10:09:59 -0700 | [diff] [blame] | 59 | void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey, |
Yangster-mac | b142cc8 | 2018-03-30 15:22:08 -0700 | [diff] [blame] | 60 | const int64_t& timestampNs) { |
Bookatz | 3e8cd35 | 2018-03-16 10:09:59 -0700 | [diff] [blame] | 61 | const auto itr = mAlarms.find(dimensionKey); |
| 62 | if (itr == mAlarms.end()) { |
| 63 | return; |
| 64 | } |
| 65 | |
| 66 | // If the alarm is set in the past but hasn't fired yet (due to lag), catch it now. |
Yangster-mac | b142cc8 | 2018-03-30 15:22:08 -0700 | [diff] [blame] | 67 | if (itr->second != nullptr && timestampNs >= (int64_t)NS_PER_SEC * itr->second->timestampSec) { |
Yao Chen | 4ce0729 | 2019-02-13 13:06:36 -0800 | [diff] [blame] | 68 | declareAnomaly(timestampNs, mAlert.metric_id(), dimensionKey, |
| 69 | mAlert.trigger_if_sum_gt() + (timestampNs / NS_PER_SEC) - |
| 70 | itr->second->timestampSec); |
Bookatz | 3e8cd35 | 2018-03-16 10:09:59 -0700 | [diff] [blame] | 71 | } |
Bookatz | 3e8cd35 | 2018-03-16 10:09:59 -0700 | [diff] [blame] | 72 | if (mAlarmMonitor != nullptr) { |
| 73 | mAlarmMonitor->remove(itr->second); |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame] | 74 | } |
Yao Chen | 1aa0002 | 2018-03-21 17:04:34 -0700 | [diff] [blame] | 75 | mAlarms.erase(dimensionKey); |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame] | 76 | } |
| 77 | |
Bookatz | 3e8cd35 | 2018-03-16 10:09:59 -0700 | [diff] [blame] | 78 | void DurationAnomalyTracker::cancelAllAlarms() { |
| 79 | if (mAlarmMonitor != nullptr) { |
| 80 | for (const auto& itr : mAlarms) { |
| 81 | mAlarmMonitor->remove(itr.second); |
| 82 | } |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame] | 83 | } |
Bookatz | 3e8cd35 | 2018-03-16 10:09:59 -0700 | [diff] [blame] | 84 | mAlarms.clear(); |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame] | 85 | } |
| 86 | |
Yangster-mac | b142cc8 | 2018-03-30 15:22:08 -0700 | [diff] [blame] | 87 | void DurationAnomalyTracker::informAlarmsFired(const int64_t& timestampNs, |
Yangster-mac | 932ecec | 2018-02-01 10:23:52 -0800 | [diff] [blame] | 88 | unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) { |
| 89 | |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame] | 90 | if (firedAlarms.empty() || mAlarms.empty()) return; |
| 91 | // Find the intersection of firedAlarms and mAlarms. |
| 92 | // The for loop is inefficient, since it loops over all keys, but that's okay since it is very |
Yangster-mac | 932ecec | 2018-02-01 10:23:52 -0800 | [diff] [blame] | 93 | // seldomly called. The alternative would be having InternalAlarms store information about the |
Yi Jin | afb3606 | 2018-01-31 19:14:25 -0800 | [diff] [blame] | 94 | // DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that |
| 95 | // is rarely ever called. |
Yangster-mac | 932ecec | 2018-02-01 10:23:52 -0800 | [diff] [blame] | 96 | unordered_map<MetricDimensionKey, sp<const InternalAlarm>> matchedAlarms; |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame] | 97 | for (const auto& kv : mAlarms) { |
| 98 | if (firedAlarms.count(kv.second) > 0) { |
| 99 | matchedAlarms.insert({kv.first, kv.second}); |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | // Now declare each of these alarms to have fired. |
| 104 | for (const auto& kv : matchedAlarms) { |
Yao Chen | 4ce0729 | 2019-02-13 13:06:36 -0800 | [diff] [blame] | 105 | declareAnomaly( |
| 106 | timestampNs, mAlert.metric_id(), kv.first, |
| 107 | mAlert.trigger_if_sum_gt() + (timestampNs / NS_PER_SEC) - kv.second->timestampSec); |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame] | 108 | mAlarms.erase(kv.first); |
| 109 | firedAlarms.erase(kv.second); // No one else can also own it, so we're done with it. |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | } // namespace statsd |
| 114 | } // namespace os |
| 115 | } // namespace android |