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

Side by Side Diff: content/browser/download/mhtml_generation_manager.cc

Issue 2364923004: Add UMA histograms to MHTML save operations. (Closed)
Patch Set: Created 4 years, 2 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/download/mhtml_generation_manager.h" 5 #include "content/browser/download/mhtml_generation_manager.h"
6 6
7 #include <map> 7 #include <map>
8 #include <queue> 8 #include <queue>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/files/file.h" 12 #include "base/files/file.h"
13 #include "base/guid.h" 13 #include "base/guid.h"
14 #include "base/macros.h" 14 #include "base/macros.h"
15 #include "base/metrics/histogram_macros.h"
15 #include "base/scoped_observer.h" 16 #include "base/scoped_observer.h"
16 #include "base/stl_util.h" 17 #include "base/stl_util.h"
17 #include "base/strings/stringprintf.h" 18 #include "base/strings/stringprintf.h"
19 #include "base/time/time.h"
18 #include "base/trace_event/trace_event.h" 20 #include "base/trace_event/trace_event.h"
19 #include "content/browser/bad_message.h" 21 #include "content/browser/bad_message.h"
20 #include "content/browser/frame_host/frame_tree_node.h" 22 #include "content/browser/frame_host/frame_tree_node.h"
21 #include "content/browser/frame_host/render_frame_host_impl.h" 23 #include "content/browser/frame_host/render_frame_host_impl.h"
22 #include "content/common/frame_messages.h" 24 #include "content/common/frame_messages.h"
23 #include "content/public/browser/browser_thread.h" 25 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/render_frame_host.h" 26 #include "content/public/browser/render_frame_host.h"
25 #include "content/public/browser/render_process_host.h" 27 #include "content/public/browser/render_process_host.h"
26 #include "content/public/browser/render_process_host_observer.h" 28 #include "content/public/browser/render_process_host_observer.h"
27 #include "content/public/browser/web_contents.h" 29 #include "content/public/browser/web_contents.h"
28 #include "content/public/common/mhtml_generation_params.h" 30 #include "content/public/common/mhtml_generation_params.h"
29 #include "net/base/mime_util.h" 31 #include "net/base/mime_util.h"
30 32
31 namespace content { 33 namespace content {
32 34
33 // The class and all of its members live on the UI thread. Only static methods 35 // The class and all of its members live on the UI thread. Only static methods
34 // are executed on other threads. 36 // are executed on other threads.
35 class MHTMLGenerationManager::Job : public RenderProcessHostObserver { 37 class MHTMLGenerationManager::Job : public RenderProcessHostObserver {
36 public: 38 public:
37 Job(int job_id, 39 Job(int job_id,
38 WebContents* web_contents, 40 WebContents* web_contents,
39 const MHTMLGenerationParams& params, 41 const MHTMLGenerationParams& params,
40 const GenerateMHTMLCallback& callback); 42 const GenerateMHTMLCallback& callback);
41 ~Job() override; 43 ~Job() override;
42 44
43 int id() const { return job_id_; } 45 int id() const { return job_id_; }
44 void set_browser_file(base::File file) { browser_file_ = std::move(file); } 46 void set_browser_file(base::File file) { browser_file_ = std::move(file); }
47 const base::TimeTicks creation_time() { return creation_time_; }
45 48
46 const GenerateMHTMLCallback& callback() const { return callback_; } 49 const GenerateMHTMLCallback& callback() const { return callback_; }
47 50
48 // Indicates whether we expect a message from the |sender| at this time. 51 // Indicates whether we expect a message from the |sender| at this time.
49 // We expect only one message per frame - therefore calling this method 52 // We expect only one message per frame - therefore calling this method
50 // will always clear |frame_tree_node_id_of_busy_frame_|. 53 // will always clear |frame_tree_node_id_of_busy_frame_|.
51 bool IsMessageFromFrameExpected(RenderFrameHostImpl* sender); 54 bool IsMessageFromFrameExpected(RenderFrameHostImpl* sender);
52 55
53 // Handler for FrameHostMsg_SerializeAsMHTMLResponse (a notification from the 56 // Handler for FrameHostMsg_SerializeAsMHTMLResponse (a notification from the
54 // renderer that the MHTML generation for previous frame has finished). 57 // renderer that the MHTML generation for previous frame has finished).
(...skipping 20 matching lines...) Expand all
75 void CloseFile(base::Callback<void(int64_t file_size)> callback); 78 void CloseFile(base::Callback<void(int64_t file_size)> callback);
76 79
77 // RenderProcessHostObserver: 80 // RenderProcessHostObserver:
78 void RenderProcessExited(RenderProcessHost* host, 81 void RenderProcessExited(RenderProcessHost* host,
79 base::TerminationStatus status, 82 base::TerminationStatus status,
80 int exit_code) override; 83 int exit_code) override;
81 void RenderProcessHostDestroyed(RenderProcessHost* host) override; 84 void RenderProcessHostDestroyed(RenderProcessHost* host) override;
82 85
83 void MarkAsFinished(); 86 void MarkAsFinished();
84 87
88 void ReportRendererMainThreadTime(base::TimeDelta renderer_main_thread_time);
89
85 private: 90 private:
86 static int64_t CloseFileOnFileThread(base::File file); 91 static int64_t CloseFileOnFileThread(base::File file);
87 void AddFrame(RenderFrameHost* render_frame_host); 92 void AddFrame(RenderFrameHost* render_frame_host);
88 93
89 // Creates a new map with values (content ids) the same as in 94 // Creates a new map with values (content ids) the same as in
90 // |frame_tree_node_to_content_id_| map, but with the keys translated from 95 // |frame_tree_node_to_content_id_| map, but with the keys translated from
91 // frame_tree_node_id into a |site_instance|-specific routing_id. 96 // frame_tree_node_id into a |site_instance|-specific routing_id.
92 std::map<int, std::string> CreateFrameRoutingIdToContentId( 97 std::map<int, std::string> CreateFrameRoutingIdToContentId(
93 SiteInstance* site_instance); 98 SiteInstance* site_instance);
94 99
95 // Id used to map renderer responses to jobs. 100 // Id used to map renderer responses to jobs.
96 // See also MHTMLGenerationManager::id_to_job_ map. 101 // See also MHTMLGenerationManager::id_to_job_ map.
97 int job_id_; 102 const int job_id_;
103
104 // Time tracking for performance metrics reporting.
105 const base::TimeTicks creation_time_;
106 base::TimeTicks wait_on_renderer_start_time_;
107 base::TimeDelta all_renderers_wait_time_;
108 base::TimeDelta all_renderers_main_thread_time_;
98 109
99 // User-configurable parameters. Includes the file location, binary encoding 110 // User-configurable parameters. Includes the file location, binary encoding
100 // choices, and whether to skip storing resources marked 111 // choices, and whether to skip storing resources marked
101 // Cache-Control: no-store. 112 // Cache-Control: no-store.
102 MHTMLGenerationParams params_; 113 MHTMLGenerationParams params_;
103 114
104 // The IDs of frames that still need to be processed. 115 // The IDs of frames that still need to be processed.
105 std::queue<int> pending_frame_tree_node_ids_; 116 std::queue<int> pending_frame_tree_node_ids_;
106 117
107 // Identifies a frame to which we've sent FrameMsg_SerializeAsMHTML but for 118 // Identifies a frame to which we've sent FrameMsg_SerializeAsMHTML but for
(...skipping 28 matching lines...) Expand all
136 observed_renderer_process_host_; 147 observed_renderer_process_host_;
137 148
138 DISALLOW_COPY_AND_ASSIGN(Job); 149 DISALLOW_COPY_AND_ASSIGN(Job);
139 }; 150 };
140 151
141 MHTMLGenerationManager::Job::Job(int job_id, 152 MHTMLGenerationManager::Job::Job(int job_id,
142 WebContents* web_contents, 153 WebContents* web_contents,
143 const MHTMLGenerationParams& params, 154 const MHTMLGenerationParams& params,
144 const GenerateMHTMLCallback& callback) 155 const GenerateMHTMLCallback& callback)
145 : job_id_(job_id), 156 : job_id_(job_id),
157 creation_time_(base::TimeTicks::Now()),
146 params_(params), 158 params_(params),
147 frame_tree_node_id_of_busy_frame_(FrameTreeNode::kFrameTreeNodeInvalidId), 159 frame_tree_node_id_of_busy_frame_(FrameTreeNode::kFrameTreeNodeInvalidId),
148 mhtml_boundary_marker_(net::GenerateMimeMultipartBoundary()), 160 mhtml_boundary_marker_(net::GenerateMimeMultipartBoundary()),
149 salt_(base::GenerateGUID()), 161 salt_(base::GenerateGUID()),
150 callback_(callback), 162 callback_(callback),
151 is_finished_(false), 163 is_finished_(false),
152 observed_renderer_process_host_(this) { 164 observed_renderer_process_host_(this) {
153 DCHECK_CURRENTLY_ON(BrowserThread::UI); 165 DCHECK_CURRENTLY_ON(BrowserThread::UI);
154 web_contents->ForEachFrame(base::Bind( 166 web_contents->ForEachFrame(base::Bind(
155 &MHTMLGenerationManager::Job::AddFrame, 167 &MHTMLGenerationManager::Job::AddFrame,
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 CreateFrameRoutingIdToContentId(rfh->GetSiteInstance()); 232 CreateFrameRoutingIdToContentId(rfh->GetSiteInstance());
221 233
222 // Send the IPC asking the renderer to serialize the frame. 234 // Send the IPC asking the renderer to serialize the frame.
223 DCHECK_EQ(FrameTreeNode::kFrameTreeNodeInvalidId, 235 DCHECK_EQ(FrameTreeNode::kFrameTreeNodeInvalidId,
224 frame_tree_node_id_of_busy_frame_); 236 frame_tree_node_id_of_busy_frame_);
225 frame_tree_node_id_of_busy_frame_ = frame_tree_node_id; 237 frame_tree_node_id_of_busy_frame_ = frame_tree_node_id;
226 rfh->Send(new FrameMsg_SerializeAsMHTML(rfh->GetRoutingID(), ipc_params)); 238 rfh->Send(new FrameMsg_SerializeAsMHTML(rfh->GetRoutingID(), ipc_params));
227 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("page-serialization", "WaitingOnRenderer", 239 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("page-serialization", "WaitingOnRenderer",
228 this, "frame tree node id", 240 this, "frame tree node id",
229 frame_tree_node_id); 241 frame_tree_node_id);
242 DCHECK(wait_on_renderer_start_time_.is_null());
243 wait_on_renderer_start_time_ = base::TimeTicks::Now();
230 return true; 244 return true;
231 } 245 }
232 246
233 void MHTMLGenerationManager::Job::RenderProcessExited( 247 void MHTMLGenerationManager::Job::RenderProcessExited(
234 RenderProcessHost* host, 248 RenderProcessHost* host,
235 base::TerminationStatus status, 249 base::TerminationStatus status,
236 int exit_code) { 250 int exit_code) {
237 DCHECK_CURRENTLY_ON(BrowserThread::UI); 251 DCHECK_CURRENTLY_ON(BrowserThread::UI);
238 MHTMLGenerationManager::GetInstance()->RenderProcessExited(this); 252 MHTMLGenerationManager::GetInstance()->RenderProcessExited(this);
239 } 253 }
240 254
241 void MHTMLGenerationManager::Job::MarkAsFinished() { 255 void MHTMLGenerationManager::Job::MarkAsFinished() {
242 DCHECK(!is_finished_); 256 DCHECK(!is_finished_);
243 is_finished_ = true; 257 is_finished_ = true;
244 TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("page-serialization", "JobFinished", 258 TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("page-serialization", "JobFinished",
245 this); 259 this);
246 260
261 // End of job timing reports.
262 if (!wait_on_renderer_start_time_.is_null()) {
263 base::TimeDelta renderer_wait_time =
264 base::TimeTicks::Now() - wait_on_renderer_start_time_;
265 UMA_HISTOGRAM_TIMES("MhtmlGeneration.BrowserWaitTimeForFrameSerialization",
266 renderer_wait_time);
267 all_renderers_wait_time_ += renderer_wait_time;
268 }
269 if (!all_renderers_wait_time_.is_zero()) {
270 UMA_HISTOGRAM_TIMES(
271 "MhtmlGeneration.BrowserWaitTimeForFrameTreeSerialization",
272 all_renderers_wait_time_);
273 }
274 if (!all_renderers_main_thread_time_.is_zero()) {
275 UMA_HISTOGRAM_TIMES(
276 "MhtmlGeneration.AllRenderersMainThreadTimeForFrameTreeSerialization",
277 all_renderers_main_thread_time_);
278 }
279
247 // Stopping RenderProcessExited notifications is needed to avoid calling 280 // Stopping RenderProcessExited notifications is needed to avoid calling
248 // JobFinished twice. See also https://crbug.com/612098. 281 // JobFinished twice. See also https://crbug.com/612098.
249 observed_renderer_process_host_.RemoveAll(); 282 observed_renderer_process_host_.RemoveAll();
250 } 283 }
251 284
285 void MHTMLGenerationManager::Job::ReportRendererMainThreadTime(
286 base::TimeDelta renderer_main_thread_time) {
287 DCHECK(renderer_main_thread_time > base::TimeDelta());
288 if (renderer_main_thread_time > base::TimeDelta())
carlosk 2016/09/24 01:30:22 This is here to avoid adding potentially bogus val
289 all_renderers_main_thread_time_ += renderer_main_thread_time;
290 }
291
252 void MHTMLGenerationManager::Job::AddFrame(RenderFrameHost* render_frame_host) { 292 void MHTMLGenerationManager::Job::AddFrame(RenderFrameHost* render_frame_host) {
253 auto* rfhi = static_cast<RenderFrameHostImpl*>(render_frame_host); 293 auto* rfhi = static_cast<RenderFrameHostImpl*>(render_frame_host);
254 int frame_tree_node_id = rfhi->frame_tree_node()->frame_tree_node_id(); 294 int frame_tree_node_id = rfhi->frame_tree_node()->frame_tree_node_id();
255 pending_frame_tree_node_ids_.push(frame_tree_node_id); 295 pending_frame_tree_node_ids_.push(frame_tree_node_id);
256 296
257 std::string guid = base::GenerateGUID(); 297 std::string guid = base::GenerateGUID();
258 std::string content_id = base::StringPrintf("<frame-%d-%s@mhtml.blink>", 298 std::string content_id = base::StringPrintf("<frame-%d-%s@mhtml.blink>",
259 frame_tree_node_id, guid.c_str()); 299 frame_tree_node_id, guid.c_str());
260 frame_tree_node_to_content_id_[frame_tree_node_id] = content_id; 300 frame_tree_node_to_content_id_[frame_tree_node_id] = content_id;
261 } 301 }
(...skipping 28 matching lines...) Expand all
290 330
291 // We only expect one message per frame - let's make sure subsequent messages 331 // We only expect one message per frame - let's make sure subsequent messages
292 // from the same |sender| will be rejected. 332 // from the same |sender| will be rejected.
293 frame_tree_node_id_of_busy_frame_ = FrameTreeNode::kFrameTreeNodeInvalidId; 333 frame_tree_node_id_of_busy_frame_ = FrameTreeNode::kFrameTreeNodeInvalidId;
294 334
295 return true; 335 return true;
296 } 336 }
297 337
298 bool MHTMLGenerationManager::Job::OnSerializeAsMHTMLResponse( 338 bool MHTMLGenerationManager::Job::OnSerializeAsMHTMLResponse(
299 const std::set<std::string>& digests_of_uris_of_serialized_resources) { 339 const std::set<std::string>& digests_of_uris_of_serialized_resources) {
340 DCHECK(!wait_on_renderer_start_time_.is_null());
341 base::TimeDelta renderer_wait_time =
342 base::TimeTicks::Now() - wait_on_renderer_start_time_;
343 UMA_HISTOGRAM_TIMES("MhtmlGeneration.BrowserWaitTimeForFrameSerialization",
344 renderer_wait_time);
345 all_renderers_wait_time_ += renderer_wait_time;
346 wait_on_renderer_start_time_ = base::TimeTicks();
347
300 // Renderer should be deduping resources with the same uris. 348 // Renderer should be deduping resources with the same uris.
301 DCHECK_EQ(0u, base::STLSetIntersection<std::set<std::string>>( 349 DCHECK_EQ(0u, base::STLSetIntersection<std::set<std::string>>(
302 digests_of_already_serialized_uris_, 350 digests_of_already_serialized_uris_,
303 digests_of_uris_of_serialized_resources).size()); 351 digests_of_uris_of_serialized_resources).size());
304 digests_of_already_serialized_uris_.insert( 352 digests_of_already_serialized_uris_.insert(
305 digests_of_uris_of_serialized_resources.begin(), 353 digests_of_uris_of_serialized_resources.begin(),
306 digests_of_uris_of_serialized_resources.end()); 354 digests_of_uris_of_serialized_resources.end());
307 355
308 if (pending_frame_tree_node_ids_.empty()) 356 if (pending_frame_tree_node_ids_.empty())
309 return true; // Report success - all frames have been processed. 357 return true; // Report success - all frames have been processed.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
346 base::Bind(&MHTMLGenerationManager::CreateFile, params.file_path), 394 base::Bind(&MHTMLGenerationManager::CreateFile, params.file_path),
347 base::Bind(&MHTMLGenerationManager::OnFileAvailable, 395 base::Bind(&MHTMLGenerationManager::OnFileAvailable,
348 base::Unretained(this), // Safe b/c |this| is a singleton. 396 base::Unretained(this), // Safe b/c |this| is a singleton.
349 job->id())); 397 job->id()));
350 } 398 }
351 399
352 void MHTMLGenerationManager::OnSerializeAsMHTMLResponse( 400 void MHTMLGenerationManager::OnSerializeAsMHTMLResponse(
353 RenderFrameHostImpl* sender, 401 RenderFrameHostImpl* sender,
354 int job_id, 402 int job_id,
355 bool mhtml_generation_in_renderer_succeeded, 403 bool mhtml_generation_in_renderer_succeeded,
356 const std::set<std::string>& digests_of_uris_of_serialized_resources) { 404 const std::set<std::string>& digests_of_uris_of_serialized_resources,
405 base::TimeDelta renderer_main_thread_time) {
357 DCHECK_CURRENTLY_ON(BrowserThread::UI); 406 DCHECK_CURRENTLY_ON(BrowserThread::UI);
358 407
359 Job* job = FindJob(job_id); 408 Job* job = FindJob(job_id);
360 if (!job || !job->IsMessageFromFrameExpected(sender)) { 409 if (!job || !job->IsMessageFromFrameExpected(sender)) {
361 NOTREACHED(); 410 NOTREACHED();
362 ReceivedBadMessage(sender->GetProcess(), 411 ReceivedBadMessage(sender->GetProcess(),
363 bad_message::DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE); 412 bad_message::DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE);
364 return; 413 return;
365 } 414 }
366 415
367 TRACE_EVENT_NESTABLE_ASYNC_END0("page-serialization", "WaitingOnRenderer", 416 TRACE_EVENT_NESTABLE_ASYNC_END0("page-serialization", "WaitingOnRenderer",
368 job); 417 job);
418 job->ReportRendererMainThreadTime(renderer_main_thread_time);
369 419
370 if (!mhtml_generation_in_renderer_succeeded) { 420 if (!mhtml_generation_in_renderer_succeeded) {
371 JobFinished(job, JobStatus::FAILURE); 421 JobFinished(job, JobStatus::FAILURE);
372 return; 422 return;
373 } 423 }
374 424
375 if (!job->OnSerializeAsMHTMLResponse( 425 if (!job->OnSerializeAsMHTMLResponse(
376 digests_of_uris_of_serialized_resources)) { 426 digests_of_uris_of_serialized_resources)) {
377 JobFinished(job, JobStatus::FAILURE); 427 JobFinished(job, JobStatus::FAILURE);
378 return; 428 return;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
436 void MHTMLGenerationManager::OnFileClosed(int job_id, 486 void MHTMLGenerationManager::OnFileClosed(int job_id,
437 JobStatus job_status, 487 JobStatus job_status,
438 int64_t file_size) { 488 int64_t file_size) {
439 DCHECK_CURRENTLY_ON(BrowserThread::UI); 489 DCHECK_CURRENTLY_ON(BrowserThread::UI);
440 490
441 Job* job = FindJob(job_id); 491 Job* job = FindJob(job_id);
442 TRACE_EVENT_NESTABLE_ASYNC_END2( 492 TRACE_EVENT_NESTABLE_ASYNC_END2(
443 "page-serialization", "SavingMhtmlJob", job, "job result", 493 "page-serialization", "SavingMhtmlJob", job, "job result",
444 job_status == JobStatus::SUCCESS ? "success" : "failure", "file size", 494 job_status == JobStatus::SUCCESS ? "success" : "failure", "file size",
445 file_size); 495 file_size);
496 UMA_HISTOGRAM_TIMES("MhtmlGeneration.FullPageSavingTime",
497 base::TimeTicks::Now() - job->creation_time());
446 job->callback().Run(job_status == JobStatus::SUCCESS ? file_size : -1); 498 job->callback().Run(job_status == JobStatus::SUCCESS ? file_size : -1);
447 id_to_job_.erase(job_id); 499 id_to_job_.erase(job_id);
448 delete job; 500 delete job;
449 } 501 }
450 502
451 MHTMLGenerationManager::Job* MHTMLGenerationManager::NewJob( 503 MHTMLGenerationManager::Job* MHTMLGenerationManager::NewJob(
452 WebContents* web_contents, 504 WebContents* web_contents,
453 const MHTMLGenerationParams& params, 505 const MHTMLGenerationParams& params,
454 const GenerateMHTMLCallback& callback) { 506 const GenerateMHTMLCallback& callback) {
455 DCHECK_CURRENTLY_ON(BrowserThread::UI); 507 DCHECK_CURRENTLY_ON(BrowserThread::UI);
(...skipping 14 matching lines...) Expand all
470 return iter->second; 522 return iter->second;
471 } 523 }
472 524
473 void MHTMLGenerationManager::RenderProcessExited(Job* job) { 525 void MHTMLGenerationManager::RenderProcessExited(Job* job) {
474 DCHECK_CURRENTLY_ON(BrowserThread::UI); 526 DCHECK_CURRENTLY_ON(BrowserThread::UI);
475 DCHECK(job); 527 DCHECK(job);
476 JobFinished(job, JobStatus::FAILURE); 528 JobFinished(job, JobStatus::FAILURE);
477 } 529 }
478 530
479 } // namespace content 531 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698