OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 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. | |
4 | |
5 #include "chrome/installer/util/experiment.h" | |
6 | |
7 #include <cmath> | |
8 | |
9 #include "base/logging.h" | |
10 | |
11 namespace installer { | |
12 | |
13 // Returns closest integer of logarithm of |x| with base |b|. | |
14 static double LogFloor(double x, double b) { | |
15 return round(log(x) / log(b)); | |
grt (UTC plus 2)
2017/05/24 13:43:38
nit: std::round
nikunjb
2017/05/30 21:45:01
Done.
| |
16 } | |
17 | |
18 // Returns the base to use for exponential buckets so that buckets | |
19 // 0,1,.. 2^|bits|-1 cover range [0, max_val]. If this function return b | |
20 // then Bucket value i will store values from [b^i, b^(i+1)] | |
21 static double ExpBucketBase(int max_val, int bits) { | |
22 return exp(log(max_val - 1) / (1 << bits)); | |
grt (UTC plus 2)
2017/05/24 13:43:38
std::exp, std::log
nikunjb
2017/05/30 21:45:01
Done.
| |
23 } | |
24 | |
25 Experiment::Experiment() = default; | |
26 Experiment::Experiment(Experiment&&) = default; | |
27 Experiment::Experiment(const Experiment&) = default; | |
28 Experiment::~Experiment() = default; | |
29 | |
30 void Experiment::InitializeFromMetrics(const ExperimentMetrics& metrics) { | |
31 *this = Experiment(); | |
32 metrics_ = metrics; | |
33 state_ = metrics.state; | |
34 group_ = metrics.group; | |
35 toast_location_ = metrics.toast_location; | |
36 toast_count_ = metrics.toast_count; | |
37 if (metrics_.last_used_bucket > 0) { | |
38 double log_base = ExpBucketBase(ExperimentMetrics::kMaxLastUsed, | |
39 ExperimentMetrics::kLastUsedBucketBits); | |
40 inactive_days_ = | |
41 static_cast<int>(round(pow(log_base, metrics_.last_used_bucket) - 1)); | |
grt (UTC plus 2)
2017/05/24 13:43:38
std::pow
nikunjb
2017/05/30 21:45:01
Done.
| |
42 if (inactive_days_ > ExperimentMetrics::kMaxLastUsed) { | |
43 inactive_days_ = ExperimentMetrics::kMaxLastUsed; | |
44 } | |
45 } | |
46 if (metrics_.session_length_bucket > 0) { | |
47 double log_base = ExpBucketBase(ExperimentMetrics::kMaxSessionLength, | |
48 ExperimentMetrics::kSessionLengthBits); | |
49 user_session_uptime_ = base::TimeDelta::FromMinutes(static_cast<int>( | |
50 round(pow(log_base, metrics_.session_length_bucket) - 1))); | |
51 if (user_session_uptime_.InMinutes() > | |
52 ExperimentMetrics::kMaxSessionLength) { | |
53 user_session_uptime_ = | |
54 base::TimeDelta::FromMinutes(ExperimentMetrics::kMaxSessionLength); | |
55 } | |
56 } | |
57 | |
58 if (metrics_.display_time_bucket > 0) { | |
59 double log_base = ExpBucketBase(ExperimentMetrics::kMaxDisplayTime, | |
60 ExperimentMetrics::kDisplayTimeBucketBits); | |
61 action_delay_ = base::TimeDelta::FromSeconds(static_cast<int>( | |
62 round(pow(log_base, metrics_.display_time_bucket) - 1))); | |
63 if (action_delay_.InSeconds() > ExperimentMetrics::kMaxDisplayTime) { | |
64 action_delay_ = | |
65 base::TimeDelta::FromSeconds(ExperimentMetrics::kMaxDisplayTime); | |
66 } | |
67 } | |
68 | |
69 if (metrics_.first_toast_offset > 0) { | |
70 // Accurate time information is not kept in |metrics|. Reconstruct | |
71 // the toast display time to the closest day. | |
72 first_display_time_ = | |
73 (base::Time::UnixEpoch() + | |
74 base::TimeDelta::FromSeconds( | |
75 ExperimentMetrics::kExperimentStartSeconds) + | |
76 base::TimeDelta::FromDays(metrics_.first_toast_offset)); | |
77 DCHECK_LE(metrics_.first_toast_offset, | |
78 ExperimentMetrics::kExperimentStartSeconds); | |
79 } | |
80 // Latest display time is not stored in experiment metrics. So, it will | |
81 // be initialized to be same as |first_display_time_| for now. | |
82 latest_display_time_ = first_display_time_; | |
83 } | |
84 | |
85 void Experiment::SetState(ExperimentMetrics::State state) { | |
86 state_ = state; | |
87 metrics_.SetState(state); | |
88 } | |
89 | |
90 void Experiment::AssignGroup(int group) { | |
91 DCHECK_GE(group, 0); | |
92 DCHECK_LT(group, ExperimentMetrics::kNumGroups); | |
93 DCHECK(metrics_.InInitialState()); | |
94 | |
95 group_ = group; | |
96 metrics_.group = group; | |
97 SetState(ExperimentMetrics::kGroupAssigned); | |
98 } | |
99 | |
100 void Experiment::SetToastLocation(ExperimentMetrics::ToastLocation location) { | |
101 DCHECK(!metrics_.InTerminalState()); | |
102 DCHECK(!metrics_.InInitialState()); | |
103 toast_location_ = location; | |
104 metrics_.toast_location = location; | |
105 } | |
106 | |
107 void Experiment::SetInactiveDays(int days) { | |
108 DCHECK(!metrics_.InTerminalState()); | |
109 DCHECK(!metrics_.InInitialState()); | |
110 DCHECK_GE(days, 0); | |
111 inactive_days_ = days; | |
112 double log_base = ExpBucketBase(ExperimentMetrics::kMaxLastUsed, | |
113 ExperimentMetrics::kLastUsedBucketBits); | |
114 metrics_.last_used_bucket = LogFloor(1 + days, log_base); | |
115 if (days > ExperimentMetrics::kMaxLastUsed) { | |
116 metrics_.last_used_bucket = | |
117 LogFloor(1 + ExperimentMetrics::kMaxLastUsed, log_base); | |
118 } | |
119 } | |
120 | |
121 void Experiment::SetToastCount(int count) { | |
122 DCHECK(!metrics_.InTerminalState()); | |
123 DCHECK(!metrics_.InInitialState()); | |
124 toast_count_ = count; | |
125 metrics_.toast_count = count; | |
126 if (count > ExperimentMetrics::kMaxToastCount) { | |
127 metrics_.toast_count = ExperimentMetrics::kMaxToastCount; | |
128 } | |
129 } | |
130 | |
131 void Experiment::SetDisplayTime(const base::Time& time) { | |
132 DCHECK(!metrics_.InTerminalState()); | |
133 DCHECK(!metrics_.InInitialState()); | |
134 if (metrics_.first_toast_offset == 0) { | |
135 // This is the first time toast is shown so add user to today's cohort. | |
136 first_display_time_ = time; | |
137 metrics_.first_toast_offset = | |
138 (time - base::Time::UnixEpoch() - | |
139 base::TimeDelta::FromSeconds( | |
140 ExperimentMetrics::kExperimentStartSeconds)) | |
141 .InDays(); | |
142 if (metrics_.first_toast_offset > ExperimentMetrics::kMaxFirstToastOffset || | |
143 metrics_.first_toast_offset < 0) { | |
144 // First display time is outside the experiment range. Invalid local time. | |
145 // Reset to highest value of first display time. | |
146 metrics_.first_toast_offset = ExperimentMetrics::kMaxFirstToastOffset; | |
147 } | |
148 } | |
149 latest_display_time_ = time; | |
150 metrics_.toast_hour = (time - time.LocalMidnight()).InHours(); | |
151 DCHECK_LE(metrics_.toast_hour, 24); | |
152 DCHECK_GE(metrics_.toast_hour, 0); | |
153 } | |
154 | |
155 void Experiment::SetUserSessionUptime(const base::TimeDelta& time_delta) { | |
156 DCHECK(!metrics_.InTerminalState()); | |
157 DCHECK(!metrics_.InInitialState()); | |
158 user_session_uptime_ = time_delta; | |
159 double log_base = ExpBucketBase(ExperimentMetrics::kMaxSessionLength, | |
160 ExperimentMetrics::kSessionLengthBits); | |
161 metrics_.session_length_bucket = | |
162 LogFloor(1 + time_delta.InMinutes(), log_base); | |
163 if (time_delta.InMinutes() > ExperimentMetrics::kMaxSessionLength) { | |
164 metrics_.session_length_bucket = | |
165 LogFloor(1 + ExperimentMetrics::kMaxSessionLength, log_base); | |
166 } | |
167 } | |
168 | |
169 void Experiment::SetActionDelay(const base::TimeDelta& time_delta) { | |
170 DCHECK(!metrics_.InTerminalState()); | |
171 DCHECK(!metrics_.InInitialState()); | |
172 action_delay_ = time_delta; | |
173 double log_base = ExpBucketBase(ExperimentMetrics::kMaxDisplayTime, | |
174 ExperimentMetrics::kDisplayTimeBucketBits); | |
175 metrics_.display_time_bucket = LogFloor(1 + time_delta.InSeconds(), log_base); | |
176 if (time_delta.InSeconds() > ExperimentMetrics::kMaxDisplayTime) { | |
177 metrics_.display_time_bucket = | |
178 LogFloor(1 + ExperimentMetrics::kMaxDisplayTime, log_base); | |
179 } | |
180 } | |
181 | |
182 } // namespace installer | |
OLD | NEW |