Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(484)

Side by Side Diff: chrome/browser/net/cache_stats.cc

Issue 10736066: Adding histograms showing fraction of page load times (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/browser/net/cache_stats.h"
6
7 #include <vector>
8
9 #include "base/hash_tables.h"
10 #include "base/metrics/histogram.h"
11 #include "base/stl_util.h"
12 #include "base/string_number_conversions.h"
13 #include "base/timer.h"
14 #include "chrome/browser/ui/tab_contents/tab_contents.h"
15 #include "content/common/view_messages.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/render_process_host.h"
18 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/resource_request_info.h"
20 #include "content/public/browser/web_contents.h"
21 #include "net/url_request/url_request.h"
22
23 using content::BrowserThread;
24 using content::ResourceRequestInfo;
25 using content::RenderViewHost;
26
27 #if defined(COMPILER_GCC)
28
29 namespace BASE_HASH_NAMESPACE {
30 template <>
31 struct hash<const net::URLRequest*> {
32 std::size_t operator()(const net::URLRequest* value) const {
33 return reinterpret_cast<std::size_t>(value);
34 }
35 };
36 }
37
38 #endif
39
40 namespace chrome_browser_net {
41
42 namespace {
43
44 bool GetRenderView(const net::URLRequest& request,
45 int* process_id, int* route_id) {
46 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(&request);
47 if (!info)
48 return false;
49
50 return info->GetAssociatedRenderView(process_id, route_id);
51 }
52
53 // Times after a load has started at which stats are collected.
54 const int kStatsCollectionTimesMs[] = {
55 500,
56 1000,
57 2000,
58 3000,
59 4000,
60 5000,
61 7500,
62 10000,
63 15000,
64 20000
65 };
66
67 } // namespace
68
69 // static
70 CacheStats* CacheStats::GetInstance() {
71 return Singleton<CacheStats>::get();
72 }
73
74 struct CacheStats::TabLoadStats {
75 int num_active_;
76 bool spinner_started_;
77 base::TimeTicks load_start_time_;
78 base::TimeTicks cache_start_time_;
79 base::TimeDelta cache_total_time_;
80 base::Timer timer_;
81 typedef base::hash_map<const net::URLRequest*, int> PerRequestNumActiveMap;
82 PerRequestNumActiveMap per_request_num_active_;
83 TabLoadStats()
84 : num_active_(0),
85 spinner_started_(false),
86 timer_(false, false) {
87 }
mmenke 2012/07/20 18:37:44 Constructor should go first. Also, add a blank li
tburkard 2012/07/20 19:36:42 Done.
88 };
89
90 CacheStatsRenderViewHostObserver::CacheStatsRenderViewHostObserver(
91 RenderViewHost* host)
92 : content::RenderViewHostObserver(host),
93 cache_stats_(CacheStats::GetInstance()),
94 is_loading_(false) {
95 int process_id = render_view_host()->GetProcess()->GetID();
96 int route_id = render_view_host()->GetRoutingID();
97 render_view_id_ = std::pair<int, int>(process_id, route_id);
98 }
99
100 bool CacheStatsRenderViewHostObserver::OnMessageReceived(
101 const IPC::Message& message) OVERRIDE {
102 IPC_BEGIN_MESSAGE_MAP(CacheStatsRenderViewHostObserver, message)
103 IPC_MESSAGE_HANDLER(ViewHostMsg_DidStartProvisionalLoadForFrame,
104 OnDidStartProvisionalLoadForFrame)
105 IPC_MESSAGE_HANDLER(ViewHostMsg_DidStopLoading, OnDidStopLoading)
106 IPC_END_MESSAGE_MAP()
107
108 return false;
109 }
110
111 void CacheStatsRenderViewHostObserver::OnDidStartProvisionalLoadForFrame(
112 int64 frame_id,
113 bool is_main_frame,
114 const GURL& opener_url,
115 const GURL& url) {
116 if (!is_main_frame)
117 return;
118 if (is_loading_)
119 OnDidStopLoading();
120 if (!url.SchemeIs("http"))
121 return;
122 is_loading_ = true;
123 NotifyCacheStats(CacheStats::SPINNER_START);
124 }
125
126 void CacheStatsRenderViewHostObserver::OnDidStopLoading() {
127 is_loading_ = false;
128 NotifyCacheStats(CacheStats::SPINNER_STOP);
mmenke 2012/07/20 18:37:44 Wonder if we should still record stats for cancell
tburkard 2012/07/20 19:36:42 I'd say so.. some pages take long to load, and the
129 }
130
131 CacheStatsRenderViewHostObserver::~CacheStatsRenderViewHostObserver() {
132 NotifyCacheStats(CacheStats::RENDERER_DESTROY);
133 }
134
135 void CacheStatsRenderViewHostObserver::NotifyCacheStats(
136 CacheStats::TabEvent event) {
137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
138 BrowserThread::PostTask(
139 BrowserThread::IO, FROM_HERE,
140 base::Bind(&CacheStats::OnTabEvent,
141 base::Unretained(cache_stats_),
142 render_view_id_, event));
143 }
144
145 CacheStats::CacheStats() :
146 registered_message_loop_destruction_observer_(false) {
147 for (int i = 0;
148 i < static_cast<int>(arraysize(kStatsCollectionTimesMs));
149 i++) {
150 final_histograms_.push_back(
151 base::LinearHistogram::FactoryGet(
152 "DiskCache.FractionCacheUseFinalPLT_" +
153 base::IntToString(kStatsCollectionTimesMs[i]),
154 0, 101, 102, base::Histogram::kUmaTargetedHistogramFlag));
155 intermediate_histograms_.push_back(
156 base::LinearHistogram::FactoryGet(
157 "DiskCache.FractionCacheUseIntermediatePLT_" +
158 base::IntToString(kStatsCollectionTimesMs[i]),
159 0, 101, 102, base::Histogram::kNoFlags));
160 }
161 DCHECK_EQ(final_histograms_.size(), arraysize(kStatsCollectionTimesMs));
162 DCHECK_EQ(intermediate_histograms_.size(),
163 arraysize(kStatsCollectionTimesMs));
164 }
165
166 CacheStats::~CacheStats() {
167 }
168
169 void CacheStats::WillDestroyCurrentMessageLoop() {
170 MessageLoop::current()->RemoveDestructionObserver(this);
171 STLDeleteValues(&tab_load_stats_);
172 registered_message_loop_destruction_observer_ = false;
173 }
174
175 CacheStats::TabLoadStats* CacheStats::GetTabLoadStats(
176 std::pair<int, int> render_view_id) {
177 if (!registered_message_loop_destruction_observer_) {
178 MessageLoop::current()->AddDestructionObserver(this);
179 registered_message_loop_destruction_observer_ = true;
180 }
181 if (tab_load_stats_.count(render_view_id) < 1)
182 tab_load_stats_[render_view_id] = new TabLoadStats();
183 return tab_load_stats_[render_view_id];
184 }
185
186 void CacheStats::RemoveTabLoadStats(std::pair<int, int> render_view_id) {
187 TabLoadStatsMap::iterator it = tab_load_stats_.find(render_view_id);
188 if (it != tab_load_stats_.end()) {
189 delete it->second;
190 tab_load_stats_.erase(it);
191 }
192 }
193
194 void CacheStats::OnCacheWaitStateChange(
195 const net::URLRequest& request,
196 net::NetworkDelegate::CacheWaitState state) {
197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
198 int process_id, route_id;
199 if (!GetRenderView(request, &process_id, &route_id))
200 return;
201 TabLoadStats* stats =
202 GetTabLoadStats(std::pair<int, int>(process_id, route_id));
203 bool newly_started = false;
204 bool newly_finished = false;
205 std::pair<TabLoadStats::PerRequestNumActiveMap::iterator, bool> insert_ret =
206 stats->per_request_num_active_.insert(
207 std::pair<const net::URLRequest*, int>(&request, 0));
208 TabLoadStats::PerRequestNumActiveMap::iterator entry = insert_ret.first;
209 DCHECK_GE(entry->second, 0);
210 switch (state) {
211 case net::NetworkDelegate::CACHE_WAIT_STATE_START:
212 if (entry->second == 0)
213 newly_started = true;
214 entry->second++;
215 break;
216 case net::NetworkDelegate::CACHE_WAIT_STATE_FINISH:
217 if (entry->second > 0) {
218 entry->second--;
219 if (entry->second == 0)
220 newly_finished = true;
221 }
222 break;
223 case net::NetworkDelegate::CACHE_WAIT_STATE_DONE:
224 if (entry->second > 0) {
225 entry->second = 0;
226 newly_finished = true;
227 }
228 break;
229 }
230 DCHECK_GE(entry->second, 0);
231 if (newly_started) {
232 DCHECK(!newly_finished);
233 if (stats->num_active_ == 0) {
234 stats->cache_start_time_ = base::TimeTicks::Now();
235 }
236 stats->num_active_++;
237 }
238 if (newly_finished) {
239 DCHECK(!newly_started);
240 if (stats->num_active_ == 1) {
241 stats->cache_total_time_ +=
242 base::TimeTicks::Now() - stats->cache_start_time_;
243 }
244 stats->num_active_--;
245 }
246 }
247
248 void CacheStats::OnTabEvent(std::pair<int, int> render_view_id,
249 TabEvent event) {
250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
251 if (event == RENDERER_DESTROY) {
252 RemoveTabLoadStats(render_view_id);
253 return;
254 }
255 TabLoadStats* stats = GetTabLoadStats(render_view_id);
256 if (event == SPINNER_START) {
257 stats->spinner_started_ = true;
258 stats->cache_total_time_ = base::TimeDelta();
259 stats->cache_start_time_ = base::TimeTicks::Now();
260 stats->load_start_time_ = base::TimeTicks::Now();
261 ScheduleTimer(stats, 0);
262 } else {
mmenke 2012/07/20 18:37:44 DCHECK_EQ(SPINNER_STOP, RENDERER_DESTROY);
tburkard 2012/07/20 19:36:42 Done.
263 stats->timer_.Stop();
264 if (stats->spinner_started_) {
265 stats->spinner_started_ = false;
266 base::TimeDelta load_time =
267 base::TimeTicks::Now() - stats->load_start_time_;
268 if (stats->num_active_ > 1)
269 stats->cache_total_time_ +=
270 base::TimeTicks::Now() - stats->cache_start_time_;
271 RecordCacheFractionHistogram(load_time, stats->cache_total_time_, true);
272 }
273 RemoveTabLoadStats(render_view_id);
274 }
275 }
276
277 void CacheStats::ScheduleTimer(TabLoadStats* stats, int timer_index) {
278 DCHECK(timer_index >= 0 &&
279 timer_index < static_cast<int>(arraysize(kStatsCollectionTimesMs)));
280 base::TimeDelta delta =
281 base::TimeDelta::FromMilliseconds(kStatsCollectionTimesMs[timer_index]);
282 delta -= base::TimeTicks::Now() - stats->load_start_time_;
283 stats->timer_.Start(FROM_HERE,
284 delta,
285 base::Bind(&CacheStats::TimerCb,
286 base::Unretained(this),
287 base::Unretained(stats),
288 timer_index));
289 }
290
291 void CacheStats::TimerCb(TabLoadStats* stats, int timer_index) {
292 DCHECK(stats->spinner_started_);
293 base::TimeDelta load_time = base::TimeTicks::Now() - stats->load_start_time_;
294 base::TimeDelta cache_time = stats->cache_total_time_;
295 if (stats->num_active_ > 1)
296 cache_time += base::TimeTicks::Now() - stats->cache_start_time_;
297 RecordCacheFractionHistogram(load_time, cache_time, false);
298 timer_index++;
299 if (timer_index < static_cast<int>(arraysize(kStatsCollectionTimesMs)))
300 ScheduleTimer(stats, timer_index);
301 }
302
303 void CacheStats::RecordCacheFractionHistogram(base::TimeDelta elapsed,
304 base::TimeDelta cache_time,
305 bool is_load_done) {
306 if (elapsed.InMilliseconds() <= 0)
307 return;
308
309 double cache_fraction =
310 static_cast<double>(cache_time.InMilliseconds()) /
311 static_cast<double>(elapsed.InMilliseconds());
312
313 DCHECK(cache_fraction >= 0.0 && cache_fraction <= 1.0);
314 int cache_fraction_percentage = cache_fraction * 100;
315 DCHECK(cache_fraction_percentage >= 0 && cache_fraction_percentage < 100);
316
317 int index = 0;
318 while (index + 1 < static_cast<int>(arraysize(kStatsCollectionTimesMs)) &&
319 base::TimeDelta::FromMilliseconds(kStatsCollectionTimesMs[index + 1]) <
320 elapsed) {
321 index++;
322 }
323
324 if (is_load_done) {
325 final_histograms_[index]->Add(cache_fraction_percentage);
326 } else {
327 intermediate_histograms_[index]->Add(cache_fraction_percentage);
328 }
329 }
330
331 } // namespace chrome_browser_net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698