blob: 1810164fdc455a2345968f94e6802d6f391bd202 [file] [log] [blame]
Thieu Le48e6d6d2011-12-06 00:40:27 +00001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/metrics.h"
6
7#include <base/lazy_instance.h>
8#include <base/logging.h>
9#include <base/string_util.h>
10#include <base/stringprintf.h>
11
12#include "shill/wifi_service.h"
13
14using std::string;
15using std::tr1::shared_ptr;
16
17namespace shill {
18
19static base::LazyInstance<Metrics> g_metrics(base::LINKER_INITIALIZED);
20
21// static
22const char Metrics::kMetricNetworkChannel[] = "Network.Shill.%s.Channel";
23const int Metrics::kMetricNetworkChannelMax = Metrics::kWiFiChannelMax;
24const char Metrics::kMetricNetworkServiceErrors[] =
25 "Network.Shill.ServiceErrors";
26const int Metrics::kMetricNetworkServiceErrorsMax = Service::kFailureMax;
27const char Metrics::kMetricTimeToConfigMilliseconds[] =
28 "Network.Shill.%s.TimeToConfig";
29const char Metrics::kMetricTimeToJoinMilliseconds[] =
30 "Network.Shill.%s.TimeToJoin";
31const char Metrics::kMetricTimeToOnlineMilliseconds[] =
32 "Network.Shill.%s.TimeToOnline";
33const char Metrics::kMetricTimeToPortalMilliseconds[] =
34 "Network.Shill.%s.TimeToPortal";
35const int Metrics::kTimerHistogramMaxMilliseconds = 45 * 1000;
36const int Metrics::kTimerHistogramMinMilliseconds = 1;
37const int Metrics::kTimerHistogramNumBuckets = 50;
38
39// static
40const uint16 Metrics::kWiFiBandwidth5MHz = 5;
41const uint16 Metrics::kWiFiBandwidth20MHz = 20;
42const uint16 Metrics::kWiFiFrequency2412 = 2412;
43const uint16 Metrics::kWiFiFrequency2472 = 2472;
44const uint16 Metrics::kWiFiFrequency2484 = 2484;
45const uint16 Metrics::kWiFiFrequency5170 = 5170;
46const uint16 Metrics::kWiFiFrequency5180 = 5180;
47const uint16 Metrics::kWiFiFrequency5230 = 5230;
48const uint16 Metrics::kWiFiFrequency5240 = 5240;
49const uint16 Metrics::kWiFiFrequency5320 = 5320;
50const uint16 Metrics::kWiFiFrequency5500 = 5500;
51const uint16 Metrics::kWiFiFrequency5700 = 5700;
52const uint16 Metrics::kWiFiFrequency5745 = 5745;
53const uint16 Metrics::kWiFiFrequency5825 = 5825;
54
55Metrics::Metrics() : library_(&metrics_library_) {
56 metrics_library_.Init();
57 chromeos_metrics::TimerReporter::set_metrics_lib(library_);
58}
59
60Metrics::~Metrics() {}
61
62// static
63Metrics *Metrics::GetInstance() {
64 return g_metrics.Pointer();
65}
66
67// static
68Metrics::WiFiChannel Metrics::WiFiFrequencyToChannel(uint16 frequency) {
69 WiFiChannel channel = kWiFiChannelUndef;
70 if (kWiFiFrequency2412 <= frequency && frequency <= kWiFiFrequency2472) {
71 if (((frequency - kWiFiFrequency2412) % kWiFiBandwidth5MHz) == 0)
72 channel = static_cast<WiFiChannel>(
73 kWiFiChannel2412 +
74 (frequency - kWiFiFrequency2412) / kWiFiBandwidth5MHz);
75 } else if (frequency == kWiFiFrequency2484) {
76 channel = kWiFiChannel2484;
77 } else if (kWiFiFrequency5170 <= frequency &&
78 frequency <= kWiFiFrequency5230) {
79 if ((frequency % kWiFiBandwidth20MHz) == 0)
80 channel = static_cast<WiFiChannel>(
81 kWiFiChannel5180 +
82 (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
83 if ((frequency % kWiFiBandwidth20MHz) == 10)
84 channel = static_cast<WiFiChannel>(
85 kWiFiChannel5170 +
86 (frequency - kWiFiFrequency5170) / kWiFiBandwidth20MHz);
87 } else if (kWiFiFrequency5240 <= frequency &&
88 frequency <= kWiFiFrequency5320) {
89 if (((frequency - kWiFiFrequency5180) % kWiFiBandwidth20MHz) == 0)
90 channel = static_cast<WiFiChannel>(
91 kWiFiChannel5180 +
92 (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
93 } else if (kWiFiFrequency5500 <= frequency &&
94 frequency <= kWiFiFrequency5700) {
95 if (((frequency - kWiFiFrequency5500) % kWiFiBandwidth20MHz) == 0)
96 channel = static_cast<WiFiChannel>(
97 kWiFiChannel5500 +
98 (frequency - kWiFiFrequency5500) / kWiFiBandwidth20MHz);
99 } else if (kWiFiFrequency5745 <= frequency &&
100 frequency <= kWiFiFrequency5825) {
101 if (((frequency - kWiFiFrequency5745) % kWiFiBandwidth20MHz) == 0)
102 channel = static_cast<WiFiChannel>(
103 kWiFiChannel5745 +
104 (frequency - kWiFiFrequency5745) / kWiFiBandwidth20MHz);
105 }
106 CHECK(kWiFiChannelUndef <= channel && channel < kWiFiChannelMax);
107
108 if (channel == kWiFiChannelUndef)
109 LOG(WARNING) << "no mapping for frequency " << frequency;
110 else
111 VLOG(3) << "map " << frequency << " to " << channel;
112
113 return channel;
114}
115
116void Metrics::RegisterService(const Service *service) {
117 shared_ptr<ServiceMetrics> service_metrics(new ServiceMetrics);
118 services_metrics_[service] = service_metrics;
119 service_metrics->service = service;
120 InitializeCommonServiceMetrics(service);
121 service->InitializeCustomMetrics();
122}
123
124void Metrics::DeregisterService(const Service *service) {
125 services_metrics_.erase(service);
126}
127
128void Metrics::AddServiceStateTransitionTimer(
129 const Service *service,
130 const string &histogram_name,
131 Service::ConnectState start_state,
132 Service::ConnectState stop_state) {
133 ServiceMetricsLookupMap::iterator it = services_metrics_.find(service);
134 if (it == services_metrics_.end()) {
135 VLOG(1) << "service not found";
136 DCHECK(false);
137 return;
138 }
139 ServiceMetrics *service_metrics = it->second.get();
140 CHECK(start_state < stop_state);
141 chromeos_metrics::TimerReporter *timer =
142 new chromeos_metrics::TimerReporter(histogram_name,
143 kTimerHistogramMinMilliseconds,
144 kTimerHistogramMaxMilliseconds,
145 kTimerHistogramNumBuckets);
146 service_metrics->timers.push_back(timer); // passes ownership.
147 service_metrics->start_on_state[start_state].push_back(timer);
148 service_metrics->stop_on_state[stop_state].push_back(timer);
149}
150
151void Metrics::NotifyDefaultServiceChanged(const Service */*service*/) {
152 // TODO(thieule): Handle the case when the default service has changed.
153 // crosbug.com/24438
154}
155
156void Metrics::NotifyServiceStateChanged(const Service *service,
157 Service::ConnectState new_state) {
158 ServiceMetricsLookupMap::iterator it = services_metrics_.find(service);
159 if (it == services_metrics_.end()) {
160 VLOG(1) << "service not found";
161 DCHECK(false);
162 return;
163 }
164 ServiceMetrics *service_metrics = it->second.get();
165 UpdateServiceStateTransitionMetrics(service_metrics, new_state);
166
167 if (new_state == Service::kStateFailure)
168 SendServiceFailure(service);
169
170 if (new_state != Service::kStateReady)
171 return;
172
173 service->SendPostReadyStateMetrics();
174}
175
176string Metrics::GetFullMetricName(const char *metric_name,
177 Technology::Identifier technology_id) {
178 string technology = Technology::NameFromIdentifier(technology_id);
179 technology[0] = base::ToUpperASCII(technology[0]);
180 return base::StringPrintf(metric_name, technology.c_str());
181}
182
183void Metrics::NotifyServiceDisconnect(const Service */*service*/,
184 bool /*manual_disconnect*/) {
185 // TODO(thieule): Handle service disconnects.
186 // crosbug.com/23253
187}
188
189void Metrics::NotifyPower() {
190 // TODO(thieule): Handle suspend and resume.
191 // crosbug.com/24440
192}
193
194bool Metrics::SendEnumToUMA(const string &name, int sample, int max) {
195 return library_->SendEnumToUMA(name, sample, max);
196}
197
198void Metrics::InitializeCommonServiceMetrics(const Service *service) {
199 Technology::Identifier technology = service->technology();
200 string histogram = GetFullMetricName(kMetricTimeToConfigMilliseconds,
201 technology);
202 AddServiceStateTransitionTimer(
203 service,
204 histogram,
205 Service::kStateConfiguring,
206 Service::kStateReady);
207 histogram = GetFullMetricName(kMetricTimeToPortalMilliseconds, technology);
208 AddServiceStateTransitionTimer(
209 service,
210 histogram,
211 Service::kStateReady,
212 Service::kStatePortal);
213 histogram = GetFullMetricName(kMetricTimeToOnlineMilliseconds, technology);
214 AddServiceStateTransitionTimer(
215 service,
216 histogram,
217 Service::kStateReady,
218 Service::kStateOnline);
219}
220
221void Metrics::UpdateServiceStateTransitionMetrics(
222 ServiceMetrics *service_metrics,
223 Service::ConnectState new_state) {
224 TimerReportersList::iterator it;
225 TimerReportersList &start_timers = service_metrics->start_on_state[new_state];
226 for (it = start_timers.begin(); it != start_timers.end(); ++it)
227 (*it)->Start();
228
229 TimerReportersList &stop_timers = service_metrics->stop_on_state[new_state];
230 for (it = stop_timers.begin(); it != stop_timers.end(); ++it) {
231 (*it)->Stop();
232 (*it)->ReportMilliseconds();
233 }
234}
235
236void Metrics::SendServiceFailure(const Service *service) {
237 library_->SendEnumToUMA(kMetricNetworkServiceErrors,
238 service->failure(),
239 kMetricNetworkServiceErrorsMax);
240}
241
242void Metrics::set_library(MetricsLibraryInterface *library) {
243 chromeos_metrics::TimerReporter::set_metrics_lib(library);
244 library_ = library;
245}
246
247} // namespace shill