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

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

Issue 2364923004: Add UMA histograms to MHTML save operations. (Closed)
Patch Set: Address code review comments. 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 base::TimeTicks creation_time() const { 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_);
257 if (is_finished_)
258 return;
259
243 is_finished_ = true; 260 is_finished_ = true;
244 TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("page-serialization", "JobFinished", 261 TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("page-serialization", "JobFinished",
245 this); 262 this);
246 263
264 // End of job timing reports.
265 if (!wait_on_renderer_start_time_.is_null()) {
266 base::TimeDelta renderer_wait_time =
267 base::TimeTicks::Now() - wait_on_renderer_start_time_;
268 UMA_HISTOGRAM_TIMES(
269 "PageSerialization.MhtmlGeneration.BrowserWaitForRendererTime."
270 "SingleFrame",
271 renderer_wait_time);
272 all_renderers_wait_time_ += renderer_wait_time;
273 }
274 if (!all_renderers_wait_time_.is_zero()) {
275 UMA_HISTOGRAM_TIMES(
276 "PageSerialization.MhtmlGeneration.BrowserWaitForRendererTime."
277 "FrameTree",
278 all_renderers_wait_time_);
279 }
280 if (!all_renderers_main_thread_time_.is_zero()) {
281 UMA_HISTOGRAM_TIMES(
282 "PageSerialization.MhtmlGeneration.RendererMainThreadTime.FrameTree",
283 all_renderers_main_thread_time_);
284 }
285
247 // Stopping RenderProcessExited notifications is needed to avoid calling 286 // Stopping RenderProcessExited notifications is needed to avoid calling
248 // JobFinished twice. See also https://crbug.com/612098. 287 // JobFinished twice. See also https://crbug.com/612098.
249 observed_renderer_process_host_.RemoveAll(); 288 observed_renderer_process_host_.RemoveAll();
250 } 289 }
251 290
291 void MHTMLGenerationManager::Job::ReportRendererMainThreadTime(
292 base::TimeDelta renderer_main_thread_time) {
293 DCHECK(renderer_main_thread_time > base::TimeDelta());
294 if (renderer_main_thread_time > base::TimeDelta())
295 all_renderers_main_thread_time_ += renderer_main_thread_time;
296 }
297
252 void MHTMLGenerationManager::Job::AddFrame(RenderFrameHost* render_frame_host) { 298 void MHTMLGenerationManager::Job::AddFrame(RenderFrameHost* render_frame_host) {
253 auto* rfhi = static_cast<RenderFrameHostImpl*>(render_frame_host); 299 auto* rfhi = static_cast<RenderFrameHostImpl*>(render_frame_host);
254 int frame_tree_node_id = rfhi->frame_tree_node()->frame_tree_node_id(); 300 int frame_tree_node_id = rfhi->frame_tree_node()->frame_tree_node_id();
255 pending_frame_tree_node_ids_.push(frame_tree_node_id); 301 pending_frame_tree_node_ids_.push(frame_tree_node_id);
256 302
257 std::string guid = base::GenerateGUID(); 303 std::string guid = base::GenerateGUID();
258 std::string content_id = base::StringPrintf("<frame-%d-%s@mhtml.blink>", 304 std::string content_id = base::StringPrintf("<frame-%d-%s@mhtml.blink>",
259 frame_tree_node_id, guid.c_str()); 305 frame_tree_node_id, guid.c_str());
260 frame_tree_node_to_content_id_[frame_tree_node_id] = content_id; 306 frame_tree_node_to_content_id_[frame_tree_node_id] = content_id;
261 } 307 }
(...skipping 28 matching lines...) Expand all
290 336
291 // We only expect one message per frame - let's make sure subsequent messages 337 // We only expect one message per frame - let's make sure subsequent messages
292 // from the same |sender| will be rejected. 338 // from the same |sender| will be rejected.
293 frame_tree_node_id_of_busy_frame_ = FrameTreeNode::kFrameTreeNodeInvalidId; 339 frame_tree_node_id_of_busy_frame_ = FrameTreeNode::kFrameTreeNodeInvalidId;
294 340
295 return true; 341 return true;
296 } 342 }
297 343
298 bool MHTMLGenerationManager::Job::OnSerializeAsMHTMLResponse( 344 bool MHTMLGenerationManager::Job::OnSerializeAsMHTMLResponse(
299 const std::set<std::string>& digests_of_uris_of_serialized_resources) { 345 const std::set<std::string>& digests_of_uris_of_serialized_resources) {
346 DCHECK(!wait_on_renderer_start_time_.is_null());
347 base::TimeDelta renderer_wait_time =
348 base::TimeTicks::Now() - wait_on_renderer_start_time_;
349 UMA_HISTOGRAM_TIMES(
350 "PageSerialization.MhtmlGeneration.BrowserWaitForRendererTime."
351 "SingleFrame",
352 renderer_wait_time);
353 all_renderers_wait_time_ += renderer_wait_time;
354 wait_on_renderer_start_time_ = base::TimeTicks();
355
300 // Renderer should be deduping resources with the same uris. 356 // Renderer should be deduping resources with the same uris.
301 DCHECK_EQ(0u, base::STLSetIntersection<std::set<std::string>>( 357 DCHECK_EQ(0u, base::STLSetIntersection<std::set<std::string>>(
302 digests_of_already_serialized_uris_, 358 digests_of_already_serialized_uris_,
303 digests_of_uris_of_serialized_resources).size()); 359 digests_of_uris_of_serialized_resources).size());
304 digests_of_already_serialized_uris_.insert( 360 digests_of_already_serialized_uris_.insert(
305 digests_of_uris_of_serialized_resources.begin(), 361 digests_of_uris_of_serialized_resources.begin(),
306 digests_of_uris_of_serialized_resources.end()); 362 digests_of_uris_of_serialized_resources.end());
307 363
308 if (pending_frame_tree_node_ids_.empty()) 364 if (pending_frame_tree_node_ids_.empty())
309 return true; // Report success - all frames have been processed. 365 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), 402 base::Bind(&MHTMLGenerationManager::CreateFile, params.file_path),
347 base::Bind(&MHTMLGenerationManager::OnFileAvailable, 403 base::Bind(&MHTMLGenerationManager::OnFileAvailable,
348 base::Unretained(this), // Safe b/c |this| is a singleton. 404 base::Unretained(this), // Safe b/c |this| is a singleton.
349 job->id())); 405 job->id()));
350 } 406 }
351 407
352 void MHTMLGenerationManager::OnSerializeAsMHTMLResponse( 408 void MHTMLGenerationManager::OnSerializeAsMHTMLResponse(
353 RenderFrameHostImpl* sender, 409 RenderFrameHostImpl* sender,
354 int job_id, 410 int job_id,
355 bool mhtml_generation_in_renderer_succeeded, 411 bool mhtml_generation_in_renderer_succeeded,
356 const std::set<std::string>& digests_of_uris_of_serialized_resources) { 412 const std::set<std::string>& digests_of_uris_of_serialized_resources,
413 base::TimeDelta renderer_main_thread_time) {
357 DCHECK_CURRENTLY_ON(BrowserThread::UI); 414 DCHECK_CURRENTLY_ON(BrowserThread::UI);
358 415
359 Job* job = FindJob(job_id); 416 Job* job = FindJob(job_id);
360 if (!job || !job->IsMessageFromFrameExpected(sender)) { 417 if (!job || !job->IsMessageFromFrameExpected(sender)) {
361 NOTREACHED(); 418 NOTREACHED();
362 ReceivedBadMessage(sender->GetProcess(), 419 ReceivedBadMessage(sender->GetProcess(),
363 bad_message::DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE); 420 bad_message::DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE);
364 return; 421 return;
365 } 422 }
366 423
367 TRACE_EVENT_NESTABLE_ASYNC_END0("page-serialization", "WaitingOnRenderer", 424 TRACE_EVENT_NESTABLE_ASYNC_END0("page-serialization", "WaitingOnRenderer",
368 job); 425 job);
426 job->ReportRendererMainThreadTime(renderer_main_thread_time);
369 427
370 if (!mhtml_generation_in_renderer_succeeded) { 428 if (!mhtml_generation_in_renderer_succeeded) {
371 JobFinished(job, JobStatus::FAILURE); 429 JobFinished(job, JobStatus::FAILURE);
372 return; 430 return;
373 } 431 }
374 432
375 if (!job->OnSerializeAsMHTMLResponse( 433 if (!job->OnSerializeAsMHTMLResponse(
376 digests_of_uris_of_serialized_resources)) { 434 digests_of_uris_of_serialized_resources)) {
377 JobFinished(job, JobStatus::FAILURE); 435 JobFinished(job, JobStatus::FAILURE);
378 return; 436 return;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
436 void MHTMLGenerationManager::OnFileClosed(int job_id, 494 void MHTMLGenerationManager::OnFileClosed(int job_id,
437 JobStatus job_status, 495 JobStatus job_status,
438 int64_t file_size) { 496 int64_t file_size) {
439 DCHECK_CURRENTLY_ON(BrowserThread::UI); 497 DCHECK_CURRENTLY_ON(BrowserThread::UI);
440 498
441 Job* job = FindJob(job_id); 499 Job* job = FindJob(job_id);
442 TRACE_EVENT_NESTABLE_ASYNC_END2( 500 TRACE_EVENT_NESTABLE_ASYNC_END2(
443 "page-serialization", "SavingMhtmlJob", job, "job result", 501 "page-serialization", "SavingMhtmlJob", job, "job result",
444 job_status == JobStatus::SUCCESS ? "success" : "failure", "file size", 502 job_status == JobStatus::SUCCESS ? "success" : "failure", "file size",
445 file_size); 503 file_size);
504 UMA_HISTOGRAM_TIMES("PageSerialization.MhtmlGeneration.FullPageSavingTime",
505 base::TimeTicks::Now() - job->creation_time());
446 job->callback().Run(job_status == JobStatus::SUCCESS ? file_size : -1); 506 job->callback().Run(job_status == JobStatus::SUCCESS ? file_size : -1);
447 id_to_job_.erase(job_id); 507 id_to_job_.erase(job_id);
448 delete job; 508 delete job;
449 } 509 }
450 510
451 MHTMLGenerationManager::Job* MHTMLGenerationManager::NewJob( 511 MHTMLGenerationManager::Job* MHTMLGenerationManager::NewJob(
452 WebContents* web_contents, 512 WebContents* web_contents,
453 const MHTMLGenerationParams& params, 513 const MHTMLGenerationParams& params,
454 const GenerateMHTMLCallback& callback) { 514 const GenerateMHTMLCallback& callback) {
455 DCHECK_CURRENTLY_ON(BrowserThread::UI); 515 DCHECK_CURRENTLY_ON(BrowserThread::UI);
(...skipping 14 matching lines...) Expand all
470 return iter->second; 530 return iter->second;
471 } 531 }
472 532
473 void MHTMLGenerationManager::RenderProcessExited(Job* job) { 533 void MHTMLGenerationManager::RenderProcessExited(Job* job) {
474 DCHECK_CURRENTLY_ON(BrowserThread::UI); 534 DCHECK_CURRENTLY_ON(BrowserThread::UI);
475 DCHECK(job); 535 DCHECK(job);
476 JobFinished(job, JobStatus::FAILURE); 536 JobFinished(job, JobStatus::FAILURE);
477 } 537 }
478 538
479 } // namespace content 539 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/download/mhtml_generation_manager.h ('k') | content/browser/frame_host/render_frame_host_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698