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