Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / components / data_reduction_proxy / browser / data_reduction_proxy_metrics.cc
blob22bd57c8263d396ba20eb6f132d167b328e0b908
1 // Copyright 2014 The Chromium 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.
5 #include "components/data_reduction_proxy/browser/data_reduction_proxy_metrics.h"
7 #include "base/metrics/histogram.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/prefs/scoped_user_pref_update.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings.h"
13 #include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
14 #include "components/data_reduction_proxy/common/data_reduction_proxy_pref_names.h"
15 #include "net/base/host_port_pair.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/proxy/proxy_retry_info.h"
18 #include "net/proxy/proxy_service.h"
19 #include "net/url_request/url_request_context.h"
21 namespace data_reduction_proxy {
23 namespace {
25 #if defined(SPDY_PROXY_AUTH_ORIGIN)
26 // A bypass delay more than this is treated as a long delay.
27 const int kLongBypassDelayInSeconds = 30 * 60;
28 #endif
30 // Increments an int64, stored as a string, in a ListPref at the specified
31 // index. The value must already exist and be a string representation of a
32 // number.
33 void AddInt64ToListPref(size_t index,
34 int64 length,
35 base::ListValue* list_update) {
36 int64 value = 0;
37 std::string old_string_value;
38 bool rv = list_update->GetString(index, &old_string_value);
39 DCHECK(rv);
40 if (rv) {
41 rv = base::StringToInt64(old_string_value, &value);
42 DCHECK(rv);
44 value += length;
45 list_update->Set(index, new base::StringValue(base::Int64ToString(value)));
48 int64 ListPrefInt64Value(const base::ListValue& list_update, size_t index) {
49 std::string string_value;
50 if (!list_update.GetString(index, &string_value)) {
51 NOTREACHED();
52 return 0;
55 int64 value = 0;
56 bool rv = base::StringToInt64(string_value, &value);
57 DCHECK(rv);
58 return value;
61 // Report UMA metrics for daily data reductions.
62 void RecordDailyContentLengthHistograms(
63 int64 original_length,
64 int64 received_length,
65 int64 original_length_with_data_reduction_enabled,
66 int64 received_length_with_data_reduction_enabled,
67 int64 original_length_via_data_reduction_proxy,
68 int64 received_length_via_data_reduction_proxy,
69 int64 https_length_with_data_reduction_enabled,
70 int64 short_bypass_length_with_data_reduction_enabled,
71 int64 long_bypass_length_with_data_reduction_enabled,
72 int64 unknown_length_with_data_reduction_enabled) {
73 // Report daily UMA only for days having received content.
74 if (original_length <= 0 || received_length <= 0)
75 return;
77 // Record metrics in KB.
78 UMA_HISTOGRAM_COUNTS(
79 "Net.DailyOriginalContentLength", original_length >> 10);
80 UMA_HISTOGRAM_COUNTS(
81 "Net.DailyContentLength", received_length >> 10);
82 int percent = 0;
83 // UMA percentage cannot be negative.
84 if (original_length > received_length) {
85 percent = (100 * (original_length - received_length)) / original_length;
87 UMA_HISTOGRAM_PERCENTAGE("Net.DailyContentSavingPercent", percent);
89 if (original_length_with_data_reduction_enabled <= 0 ||
90 received_length_with_data_reduction_enabled <= 0) {
91 return;
94 UMA_HISTOGRAM_COUNTS(
95 "Net.DailyOriginalContentLength_DataReductionProxyEnabled",
96 original_length_with_data_reduction_enabled >> 10);
97 UMA_HISTOGRAM_COUNTS(
98 "Net.DailyContentLength_DataReductionProxyEnabled",
99 received_length_with_data_reduction_enabled >> 10);
101 int percent_data_reduction_proxy_enabled = 0;
102 // UMA percentage cannot be negative.
103 if (original_length_with_data_reduction_enabled >
104 received_length_with_data_reduction_enabled) {
105 percent_data_reduction_proxy_enabled =
106 100 * (original_length_with_data_reduction_enabled -
107 received_length_with_data_reduction_enabled) /
108 original_length_with_data_reduction_enabled;
110 UMA_HISTOGRAM_PERCENTAGE(
111 "Net.DailyContentSavingPercent_DataReductionProxyEnabled",
112 percent_data_reduction_proxy_enabled);
114 UMA_HISTOGRAM_PERCENTAGE(
115 "Net.DailyContentPercent_DataReductionProxyEnabled",
116 (100 * received_length_with_data_reduction_enabled) / received_length);
118 DCHECK_GE(https_length_with_data_reduction_enabled, 0);
119 UMA_HISTOGRAM_COUNTS(
120 "Net.DailyContentLength_DataReductionProxyEnabled_Https",
121 https_length_with_data_reduction_enabled >> 10);
122 UMA_HISTOGRAM_PERCENTAGE(
123 "Net.DailyContentPercent_DataReductionProxyEnabled_Https",
124 (100 * https_length_with_data_reduction_enabled) / received_length);
126 DCHECK_GE(short_bypass_length_with_data_reduction_enabled, 0);
127 UMA_HISTOGRAM_COUNTS(
128 "Net.DailyContentLength_DataReductionProxyEnabled_ShortBypass",
129 short_bypass_length_with_data_reduction_enabled >> 10);
130 UMA_HISTOGRAM_PERCENTAGE(
131 "Net.DailyContentPercent_DataReductionProxyEnabled_ShortBypass",
132 ((100 * short_bypass_length_with_data_reduction_enabled) /
133 received_length));
135 DCHECK_GE(long_bypass_length_with_data_reduction_enabled, 0);
136 UMA_HISTOGRAM_COUNTS(
137 "Net.DailyContentLength_DataReductionProxyEnabled_LongBypass",
138 long_bypass_length_with_data_reduction_enabled >> 10);
139 UMA_HISTOGRAM_PERCENTAGE(
140 "Net.DailyContentPercent_DataReductionProxyEnabled_LongBypass",
141 ((100 * long_bypass_length_with_data_reduction_enabled) /
142 received_length));
144 DCHECK_GE(unknown_length_with_data_reduction_enabled, 0);
145 UMA_HISTOGRAM_COUNTS(
146 "Net.DailyContentLength_DataReductionProxyEnabled_Unknown",
147 unknown_length_with_data_reduction_enabled >> 10);
148 UMA_HISTOGRAM_PERCENTAGE(
149 "Net.DailyContentPercent_DataReductionProxyEnabled_Unknown",
150 ((100 * unknown_length_with_data_reduction_enabled) /
151 received_length));
153 DCHECK_GE(original_length_via_data_reduction_proxy, 0);
154 UMA_HISTOGRAM_COUNTS(
155 "Net.DailyOriginalContentLength_ViaDataReductionProxy",
156 original_length_via_data_reduction_proxy >> 10);
157 DCHECK_GE(received_length_via_data_reduction_proxy, 0);
158 UMA_HISTOGRAM_COUNTS(
159 "Net.DailyContentLength_ViaDataReductionProxy",
160 received_length_via_data_reduction_proxy >> 10);
161 int percent_via_data_reduction_proxy = 0;
162 if (original_length_via_data_reduction_proxy >
163 received_length_via_data_reduction_proxy) {
164 percent_via_data_reduction_proxy =
165 100 * (original_length_via_data_reduction_proxy -
166 received_length_via_data_reduction_proxy) /
167 original_length_via_data_reduction_proxy;
169 UMA_HISTOGRAM_PERCENTAGE(
170 "Net.DailyContentSavingPercent_ViaDataReductionProxy",
171 percent_via_data_reduction_proxy);
172 UMA_HISTOGRAM_PERCENTAGE(
173 "Net.DailyContentPercent_ViaDataReductionProxy",
174 (100 * received_length_via_data_reduction_proxy) / received_length);
177 // Ensure list has exactly |length| elements, either by truncating at the
178 // front, or appending "0"'s to the back.
179 void MaintainContentLengthPrefsWindow(base::ListValue* list, size_t length) {
180 // Remove data for old days from the front.
181 while (list->GetSize() > length)
182 list->Remove(0, NULL);
183 // Newly added lists are empty. Add entries to back to fill the window,
184 // each initialized to zero.
185 while (list->GetSize() < length)
186 list->AppendString(base::Int64ToString(0));
187 DCHECK_EQ(length, list->GetSize());
190 // DailyContentLengthUpdate maintains a data saving pref. The pref is a list
191 // of |kNumDaysInHistory| elements of daily total content lengths for the past
192 // |kNumDaysInHistory| days.
193 class DailyContentLengthUpdate {
194 public:
195 DailyContentLengthUpdate(
196 const char* pref,
197 PrefService* pref_service)
198 : update_(pref_service, pref) {
201 void UpdateForDataChange(int days_since_last_update) {
202 // New empty lists may have been created. Maintain the invariant that
203 // there should be exactly |kNumDaysInHistory| days in the histories.
204 MaintainContentLengthPrefsWindow(update_.Get(), kNumDaysInHistory);
205 if (days_since_last_update) {
206 MaintainContentLengthPrefForDateChange(days_since_last_update);
210 // Update the lengths for the current day.
211 void Add(int content_length) {
212 AddInt64ToListPref(kNumDaysInHistory - 1, content_length, update_.Get());
215 int64 GetListPrefValue(size_t index) {
216 return ListPrefInt64Value(*update_, index);
219 private:
220 // Update the list for date change and ensure the list has exactly |length|
221 // elements. The last entry in the list will be for the current day after
222 // the update.
223 void MaintainContentLengthPrefForDateChange(int days_since_last_update) {
224 if (days_since_last_update == -1) {
225 // The system may go backwards in time by up to a day for legitimate
226 // reasons, such as with changes to the time zone. In such cases, we
227 // keep adding to the current day.
228 // Note: we accept the fact that some reported data is shifted to
229 // the adjacent day if users travel back and forth across time zones.
230 days_since_last_update = 0;
231 } else if (days_since_last_update < -1) {
232 // Erase all entries if the system went backwards in time by more than
233 // a day.
234 update_->Clear();
236 days_since_last_update = kNumDaysInHistory;
238 DCHECK_GE(days_since_last_update, 0);
240 // Add entries for days since last update event. This will make the
241 // lists longer than kNumDaysInHistory. The additional items will be cut off
242 // from the head of the lists by |MaintainContentLengthPrefsWindow|, below.
243 for (int i = 0;
244 i < days_since_last_update && i < static_cast<int>(kNumDaysInHistory);
245 ++i) {
246 update_->AppendString(base::Int64ToString(0));
249 // Entries for new days may have been appended. Maintain the invariant that
250 // there should be exactly |kNumDaysInHistory| days in the histories.
251 MaintainContentLengthPrefsWindow(update_.Get(), kNumDaysInHistory);
254 ListPrefUpdate update_;
257 // DailyDataSavingUpdate maintains a pair of data saving prefs, original_update_
258 // and received_update_. pref_original is a list of |kNumDaysInHistory| elements
259 // of daily total original content lengths for the past |kNumDaysInHistory|
260 // days. pref_received is the corresponding list of the daily total received
261 // content lengths.
262 class DailyDataSavingUpdate {
263 public:
264 DailyDataSavingUpdate(
265 const char* pref_original,
266 const char* pref_received,
267 PrefService* pref_service)
268 : original_(pref_original, pref_service),
269 received_(pref_received, pref_service) {
272 void UpdateForDataChange(int days_since_last_update) {
273 original_.UpdateForDataChange(days_since_last_update);
274 received_.UpdateForDataChange(days_since_last_update);
277 // Update the lengths for the current day.
278 void Add(int original_content_length, int received_content_length) {
279 original_.Add(original_content_length);
280 received_.Add(received_content_length);
283 int64 GetOriginalListPrefValue(size_t index) {
284 return original_.GetListPrefValue(index);
286 int64 GetReceivedListPrefValue(size_t index) {
287 return received_.GetListPrefValue(index);
290 private:
291 DailyContentLengthUpdate original_;
292 DailyContentLengthUpdate received_;
295 } // namespace
297 DataReductionProxyRequestType GetDataReductionProxyRequestType(
298 const net::URLRequest* request) {
299 if (request->url().SchemeIs("https"))
300 return HTTPS;
301 if (!request->url().SchemeIs("http")) {
302 NOTREACHED();
303 return UNKNOWN_TYPE;
305 #if defined(SPDY_PROXY_AUTH_ORIGIN)
306 DataReductionProxyParams params(
307 DataReductionProxyParams::kAllowed |
308 DataReductionProxyParams::kFallbackAllowed |
309 DataReductionProxyParams::kPromoAllowed);
310 base::TimeDelta bypass_delay;
311 if (params.AreDataReductionProxiesBypassed(*request, &bypass_delay)) {
312 if (bypass_delay > base::TimeDelta::FromSeconds(kLongBypassDelayInSeconds))
313 return LONG_BYPASS;
314 return SHORT_BYPASS;
316 #endif
317 if (request->response_info().headers.get() &&
318 HasDataReductionProxyViaHeader(request->response_info().headers.get(),
319 NULL)) {
320 return VIA_DATA_REDUCTION_PROXY;
322 return UNKNOWN_TYPE;
325 int64 GetAdjustedOriginalContentLength(
326 DataReductionProxyRequestType request_type,
327 int64 original_content_length,
328 int64 received_content_length) {
329 // Since there was no indication of the original content length, presume
330 // it is no different from the number of bytes read.
331 if (original_content_length == -1 ||
332 request_type != VIA_DATA_REDUCTION_PROXY) {
333 return received_content_length;
335 return original_content_length;
338 void UpdateContentLengthPrefsForDataReductionProxy(
339 int received_content_length,
340 int original_content_length,
341 bool with_data_reduction_proxy_enabled,
342 DataReductionProxyRequestType request_type,
343 base::Time now, PrefService* prefs) {
344 // TODO(bengr): Remove this check once the underlying cause of
345 // http://crbug.com/287821 is fixed. For now, only continue if the current
346 // year is reported as being between 1972 and 2970.
347 base::TimeDelta time_since_unix_epoch = now - base::Time::UnixEpoch();
348 const int kMinDaysSinceUnixEpoch = 365 * 2; // 2 years.
349 const int kMaxDaysSinceUnixEpoch = 365 * 1000; // 1000 years.
350 if (time_since_unix_epoch.InDays() < kMinDaysSinceUnixEpoch ||
351 time_since_unix_epoch.InDays() > kMaxDaysSinceUnixEpoch) {
352 return;
355 // Determine how many days it has been since the last update.
356 int64 then_internal = prefs->GetInt64(
357 data_reduction_proxy::prefs::kDailyHttpContentLengthLastUpdateDate);
359 #if defined(OS_WIN)
360 base::Time then_midnight = base::Time::FromInternalValue(then_internal);
361 base::Time midnight =
362 base::Time::FromInternalValue(
363 (now.ToInternalValue() / base::Time::kMicrosecondsPerDay) *
364 base::Time::kMicrosecondsPerDay);
365 #else
366 // Local midnight could have been shifted due to time zone change.
367 base::Time then_midnight =
368 base::Time::FromInternalValue(then_internal).LocalMidnight();
369 base::Time midnight = now.LocalMidnight();
370 #endif
372 int days_since_last_update = (midnight - then_midnight).InDays();
374 // Each day, we calculate the total number of bytes received and the total
375 // size of all corresponding resources before any data-reducing recompression
376 // is applied. These values are used to compute the data savings realized
377 // by applying our compression techniques. Totals for the last
378 // |kNumDaysInHistory| days are maintained.
379 DailyDataSavingUpdate total(
380 data_reduction_proxy::prefs::kDailyHttpOriginalContentLength,
381 data_reduction_proxy::prefs::kDailyHttpReceivedContentLength,
382 prefs);
383 total.UpdateForDataChange(days_since_last_update);
385 DailyDataSavingUpdate proxy_enabled(
386 data_reduction_proxy::prefs::
387 kDailyOriginalContentLengthWithDataReductionProxyEnabled,
388 data_reduction_proxy::prefs::
389 kDailyContentLengthWithDataReductionProxyEnabled,
390 prefs);
391 proxy_enabled.UpdateForDataChange(days_since_last_update);
393 DailyDataSavingUpdate via_proxy(
394 data_reduction_proxy::prefs::
395 kDailyOriginalContentLengthViaDataReductionProxy,
396 data_reduction_proxy::prefs::
397 kDailyContentLengthViaDataReductionProxy,
398 prefs);
399 via_proxy.UpdateForDataChange(days_since_last_update);
401 DailyContentLengthUpdate https(
402 data_reduction_proxy::prefs::
403 kDailyContentLengthHttpsWithDataReductionProxyEnabled,
404 prefs);
405 https.UpdateForDataChange(days_since_last_update);
407 DailyContentLengthUpdate short_bypass(
408 data_reduction_proxy::prefs::
409 kDailyContentLengthShortBypassWithDataReductionProxyEnabled,
410 prefs);
411 short_bypass.UpdateForDataChange(days_since_last_update);
413 DailyContentLengthUpdate long_bypass(
414 data_reduction_proxy::prefs::
415 kDailyContentLengthLongBypassWithDataReductionProxyEnabled,
416 prefs);
417 long_bypass.UpdateForDataChange(days_since_last_update);
419 DailyContentLengthUpdate unknown(
420 data_reduction_proxy::prefs::
421 kDailyContentLengthUnknownWithDataReductionProxyEnabled,
422 prefs);
423 unknown.UpdateForDataChange(days_since_last_update);
425 total.Add(original_content_length, received_content_length);
426 if (with_data_reduction_proxy_enabled) {
427 proxy_enabled.Add(original_content_length, received_content_length);
428 // Ignore data source cases, if exist, when
429 // "with_data_reduction_proxy_enabled == false"
430 switch (request_type) {
431 case VIA_DATA_REDUCTION_PROXY:
432 via_proxy.Add(original_content_length, received_content_length);
433 break;
434 case HTTPS:
435 https.Add(received_content_length);
436 break;
437 case SHORT_BYPASS:
438 short_bypass.Add(received_content_length);
439 break;
440 case LONG_BYPASS:
441 long_bypass.Add(received_content_length);
442 break;
443 case UNKNOWN_TYPE:
444 unknown.Add(received_content_length);
445 break;
449 if (days_since_last_update) {
450 // Record the last update time in microseconds in UTC.
451 prefs->SetInt64(
452 data_reduction_proxy::prefs::kDailyHttpContentLengthLastUpdateDate,
453 midnight.ToInternalValue());
455 // A new day. Report the previous day's data if exists. We'll lose usage
456 // data if the last time Chrome was run was more than a day ago.
457 // Here, we prefer collecting less data but the collected data is
458 // associated with an accurate date.
459 if (days_since_last_update == 1) {
460 // The previous day's data point is the second one from the tail.
461 // Therefore (kNumDaysInHistory - 2) below.
462 RecordDailyContentLengthHistograms(
463 total.GetOriginalListPrefValue(kNumDaysInHistory - 2),
464 total.GetReceivedListPrefValue(kNumDaysInHistory - 2),
465 proxy_enabled.GetOriginalListPrefValue(kNumDaysInHistory - 2),
466 proxy_enabled.GetReceivedListPrefValue(kNumDaysInHistory - 2),
467 via_proxy.GetOriginalListPrefValue(kNumDaysInHistory - 2),
468 via_proxy.GetReceivedListPrefValue(kNumDaysInHistory - 2),
469 https.GetListPrefValue(kNumDaysInHistory - 2),
470 short_bypass.GetListPrefValue(kNumDaysInHistory - 2),
471 long_bypass.GetListPrefValue(kNumDaysInHistory - 2),
472 unknown.GetListPrefValue(kNumDaysInHistory - 2));
477 void UpdateContentLengthPrefs(
478 int received_content_length,
479 int original_content_length,
480 bool with_data_reduction_proxy_enabled,
481 DataReductionProxyRequestType request_type,
482 PrefService* prefs) {
483 int64 total_received = prefs->GetInt64(
484 data_reduction_proxy::prefs::kHttpReceivedContentLength);
485 int64 total_original = prefs->GetInt64(
486 data_reduction_proxy::prefs::kHttpOriginalContentLength);
487 total_received += received_content_length;
488 total_original += original_content_length;
489 prefs->SetInt64(data_reduction_proxy::prefs::kHttpReceivedContentLength,
490 total_received);
491 prefs->SetInt64(data_reduction_proxy::prefs::kHttpOriginalContentLength,
492 total_original);
494 UpdateContentLengthPrefsForDataReductionProxy(
495 received_content_length,
496 original_content_length,
497 with_data_reduction_proxy_enabled,
498 request_type,
499 base::Time::Now(),
500 prefs);
503 } // namespace data_reduction_proxy