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

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/public/browser/browser_thread.h"
16 #include "content/public/browser/render_process_host.h"
17 #include "content/public/browser/render_view_host.h"
18 #include "content/public/browser/resource_request_info.h"
19 #include "content/public/browser/web_contents.h"
20 #include "net/url_request/url_request.h"
21 #include <stdio.h>
mmenke 2012/07/19 17:55:34 Fix include order.
tburkard 2012/07/19 22:54:33 Done.
22
23 using content::BrowserThread;
24 using content::ResourceRequestInfo;
25
26 #if defined(COMPILER_GCC)
27
28 namespace BASE_HASH_NAMESPACE {
29 template <>
30 struct hash<const net::URLRequest*> {
31 std::size_t operator()(const net::URLRequest* value) const {
32 return reinterpret_cast<std::size_t>(value);
33 }
34 };
35 }
36
37 #endif
38
39 namespace chrome_browser_net {
40
41 namespace {
42
43 bool GetRenderView(const net::URLRequest& request,
44 int* process_id, int* route_id) {
45 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(&request);
46 if (!info)
47 return false;
48
49 return info->GetAssociatedRenderView(process_id, route_id);
50 }
51
52 // Times after a load has started at which stats are collected.
53 const int kStatsCollectionTimesMs[] = {
54 500,
55 1000,
56 2000,
57 3000,
58 4000,
59 5000,
60 7500,
61 10000,
62 15000,
63 20000
64 };
65
66 } // namespace
67
68 // static
69 CacheStats* CacheStats::GetInstance() {
70 return Singleton<CacheStats>::get();
71 }
72
73 struct CacheStats::TabLoadStats {
74 int num_active_;
75 base::TimeTicks load_start_time_;
76 base::TimeTicks cache_start_time_;
77 base::TimeDelta cache_total_time_;
78 base::Timer timer_;
79 typedef base::hash_map<const net::URLRequest*, int> PerRequestNumActiveMap;
80 PerRequestNumActiveMap per_request_num_active_;
81 TabLoadStats()
82 : num_active_(0),
83 timer_(false, false) {
84 }
85 };
86
87 CacheStatsTabHelper::CacheStatsTabHelper(TabContents* tab)
88 : content::WebContentsObserver(tab->web_contents()),
89 cache_stats_(CacheStats::GetInstance()),
90 is_loading_(false),
91 render_view_id_initialized_(false) {
92 }
93
94 CacheStatsTabHelper::~CacheStatsTabHelper() {
95 DidStopLoading();
96 if (render_view_id_initialized_)
97 NotifyCacheStats(CacheStats::RENDERER_DESTROY);
98 }
99
100 void CacheStatsTabHelper::DidStartProvisionalLoadForFrame(
101 int64 frame_id,
102 bool is_main_frame,
103 const GURL& validated_url,
104 bool is_error_page,
105 content::RenderViewHost* render_view_host) {
mmenke 2012/07/19 17:55:34 Fix indent
tburkard 2012/07/19 22:54:33 Done.
106 if (!render_view_id_initialized_)
107 return;
108 if (!is_main_frame)
109 return;
110 if (!validated_url.SchemeIs("http"))
111 return;
112 // If is_loading_ is already true, it means the user navigated to a new
113 // URL while the old URL is still in progress. That is ok, we will
114 // just reset the metrics for the new page load in this case.
115 if (is_loading_)
116 NotifyCacheStats(CacheStats::SPINNER_STOP);
117 is_loading_ = true;
118 NotifyCacheStats(CacheStats::SPINNER_START);
119 }
120
121 void CacheStatsTabHelper::DidStopLoading() {
122 if (!is_loading_)
123 return;
124 is_loading_ = false;
125 NotifyCacheStats(CacheStats::SPINNER_STOP);
mmenke 2012/07/19 17:55:34 It's actually possible for this not to be for the
tburkard 2012/07/19 22:54:33 will fix separately. On 2012/07/19 17:55:34, Matt
126 }
127
128 void CacheStatsTabHelper::RenderViewCreated(
129 content::RenderViewHost* render_view_host) {
130 DidStopLoading();
131 if (render_view_id_initialized_)
132 NotifyCacheStats(CacheStats::RENDERER_DESTROY);
mmenke 2012/07/19 17:55:34 This is incorrect - if it's a cross process naviga
tburkard 2012/07/19 22:54:33 will fix separately. On 2012/07/19 17:55:34, Matt
133 int process_id = render_view_host->GetProcess()->GetID();
134 int route_id = render_view_host->GetRoutingID();
135 render_view_id_ = std::pair<int, int>(process_id, route_id);
136 render_view_id_initialized_ = true;
137 }
138
139 void CacheStatsTabHelper::NotifyCacheStats(CacheStats::TabEvent event) {
mmenke 2012/07/19 17:55:34 Fix indent
tburkard 2012/07/19 22:54:33 Done.
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
141 BrowserThread::PostTask(
142 BrowserThread::IO, FROM_HERE,
143 base::Bind(&CacheStats::OnTabEvent,
144 base::Unretained(cache_stats_),
145 render_view_id_, event));
146 }
147
148 CacheStats::CacheStats() :
149 registered_message_loop_destruction_observer_(false) {
150 for (int i = 0;
151 i < static_cast<int>(arraysize(kStatsCollectionTimesMs));
152 i++) {
153 final_histograms_.push_back(
154 base::LinearHistogram::FactoryGet(
155 "DiskCache.FractionCacheUseFinalPLT_" +
156 base::IntToString(kStatsCollectionTimesMs[i]),
157 0, 101, 102, base::Histogram::kUmaTargetedHistogramFlag));
158 intermediate_histograms_.push_back(
159 base::LinearHistogram::FactoryGet(
160 "DiskCache.FractionCacheUseIntermediatePLT_" +
161 base::IntToString(kStatsCollectionTimesMs[i]),
162 0, 101, 102, base::Histogram::kNoFlags));
163 }
164 DCHECK(final_histograms_.size() == arraysize(kStatsCollectionTimesMs));
165 DCHECK(intermediate_histograms_.size() == arraysize(kStatsCollectionTimesMs));
mmenke 2012/07/19 17:55:34 DCHECK_EQ?
tburkard 2012/07/19 22:54:33 Done.
166 }
167
168 CacheStats::~CacheStats() {
169 }
170
171 void CacheStats::WillDestroyCurrentMessageLoop() {
172 MessageLoop::current()->RemoveDestructionObserver(this);
173 STLDeleteValues(&tab_load_stats_);
174 registered_message_loop_destruction_observer_ = false;
175 }
176
177 CacheStats::TabLoadStats* CacheStats::GetTabLoadStats(
178 std::pair<int, int> render_view_id) {
179 if (!registered_message_loop_destruction_observer_) {
180 MessageLoop::current()->AddDestructionObserver(this);
181 registered_message_loop_destruction_observer_ = true;
182 }
183 if (tab_load_stats_.count(render_view_id) < 1)
184 tab_load_stats_[render_view_id] = new TabLoadStats();
185 return tab_load_stats_[render_view_id];
186 }
187
188 void CacheStats::RemoveTabLoadStats(std::pair<int, int> render_view_id) {
189 TabLoadStatsMap::iterator it = tab_load_stats_.find(render_view_id);
190 if (it != tab_load_stats_.end()) {
191 delete it->second;
192 tab_load_stats_.erase(it);
193 }
194 }
195
196 void CacheStats::OnCacheWaitStateChange(
197 const net::URLRequest& request,
198 net::NetworkDelegate::CacheWaitState state) {
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
200 int render_view, route_id;
mmenke 2012/07/19 17:55:34 render_view should be process_id.
tburkard 2012/07/19 22:54:33 Done.
201 if (!GetRenderView(request, &render_view, &route_id))
202 return;
203 TabLoadStats* stats =
204 GetTabLoadStats(std::pair<int, int>(render_view, route_id));
205 bool newly_started = false;
206 bool newly_finished = false;
207 std::pair<TabLoadStats::PerRequestNumActiveMap::iterator, bool> insert_ret =
208 stats->per_request_num_active_.insert(
209 std::pair<const net::URLRequest*, int>(&request, 0));
210 TabLoadStats::PerRequestNumActiveMap::iterator entry = insert_ret.first;
211 DCHECK(entry->second >= 0);
212 switch (state) {
213 case net::NetworkDelegate::CACHE_WAIT_STATE_START:
214 if (entry->second == 0)
215 newly_started = true;
216 entry->second++;
217 break;
218 case net::NetworkDelegate::CACHE_WAIT_STATE_FINISH:
219 if (entry->second > 0) {
220 entry->second--;
221 if (entry->second == 0)
222 newly_finished = true;
223 }
224 break;
225 case net::NetworkDelegate::CACHE_WAIT_STATE_DONE:
226 if (entry->second > 0) {
227 entry->second = 0;
228 newly_finished = true;
229 }
230 break;
231 }
232 DCHECK(entry->second >= 0);
mmenke 2012/07/19 17:55:34 DCHECK_GE?
tburkard 2012/07/19 22:54:33 Done.
233 DCHECK(!newly_started || !newly_finished);
mmenke 2012/07/19 17:55:34 I find this a little hard to follow. I'd suggest
tburkard 2012/07/19 22:54:33 Done.
234 if (newly_started) {
235 if (stats->num_active_ == 0) {
236 stats->cache_start_time_ = base::TimeTicks::Now();
237 }
238 stats->num_active_++;
239 }
240 if (newly_finished) {
241 if (stats->num_active_ == 1) {
242 stats->cache_total_time_ +=
243 base::TimeTicks::Now() - stats->cache_start_time_;
mmenke 2012/07/19 17:55:34 Should we remove it from the map? Otherwise, as l
tburkard 2012/07/19 22:54:33 will fix separately. On 2012/07/19 17:55:34, Matt
244 }
245 stats->num_active_--;
246 }
247 }
248
249 void CacheStats::OnTabEvent(std::pair<int, int> render_view_id,
250 TabEvent event) {
251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
252 if (event == RENDERER_DESTROY) {
253 RemoveTabLoadStats(render_view_id);
254 return;
255 }
256 TabLoadStats* stats = GetTabLoadStats(render_view_id);
257 if (event == SPINNER_START) {
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 {
263 stats->timer_.Stop();
264 base::TimeDelta load_time =
265 base::TimeTicks::Now() - stats->load_start_time_;
266 if (stats->num_active_ > 1)
267 stats->cache_total_time_ +=
268 base::TimeTicks::Now() - stats->cache_start_time_;
269 RecordCacheFractionHistogram(load_time, stats->cache_total_time_, true);
270 RemoveTabLoadStats(render_view_id);
mmenke 2012/07/19 17:55:34 So when navigating though an HTTPS site...We just
tburkard 2012/07/19 22:54:33 will fix separately. On 2012/07/19 17:55:34, Matt
271 }
272 }
273
274 void CacheStats::ScheduleTimer(TabLoadStats* stats, int timer_index) {
275 DCHECK(timer_index >= 0 &&
276 timer_index < static_cast<int>(arraysize(kStatsCollectionTimesMs)));
277 base::TimeDelta delta =
278 base::TimeDelta::FromMilliseconds(kStatsCollectionTimesMs[timer_index]);
279 delta -= base::TimeTicks::Now() - stats->load_start_time_;
280 stats->timer_.Start(FROM_HERE,
281 delta,
282 base::Bind(&CacheStats::TimerCb,
283 base::Unretained(this),
284 base::Unretained(stats),
285 timer_index));
286 }
287
288 void CacheStats::TimerCb(TabLoadStats* stats, int timer_index) {
289 base::TimeDelta load_time = base::TimeTicks::Now() - stats->load_start_time_;
290 base::TimeDelta cache_time = stats->cache_total_time_;
291 if (stats->num_active_ > 1)
292 cache_time += base::TimeTicks::Now() - stats->cache_start_time_;
293 RecordCacheFractionHistogram(load_time, cache_time, false);
294 timer_index++;
295 if (timer_index < static_cast<int>(arraysize(kStatsCollectionTimesMs)))
296 ScheduleTimer(stats, timer_index);
297 }
298
299 void CacheStats::RecordCacheFractionHistogram(base::TimeDelta elapsed,
300 base::TimeDelta cache_time,
301 bool is_load_done) {
302 if (elapsed.InMilliseconds() <= 0)
303 return;
304
305 double cache_fraction =
306 static_cast<double>(cache_time.InMilliseconds()) /
307 static_cast<double>(elapsed.InMilliseconds());
308
309 DCHECK(cache_fraction >= 0.0 && cache_fraction <= 1.0);
310 int cache_fraction_percentage = cache_fraction * 100;
311 DCHECK(cache_fraction_percentage >= 0 && cache_fraction_percentage < 100);
312
313 int index = 0;
314 while (index + 1 < static_cast<int>(arraysize(kStatsCollectionTimesMs)) &&
315 base::TimeDelta::FromMilliseconds(kStatsCollectionTimesMs[index + 1]) <
316 elapsed) {
317 index++;
318 }
319
320 if (is_load_done) {
321 final_histograms_[index]->Add(cache_fraction_percentage);
322 } else {
323 intermediate_histograms_[index]->Add(cache_fraction_percentage);
324 }
325 }
326
327 } // namespace chrome_browser_net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698