Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / loader / resource_scheduler.cc
index 0dd93f3..82d96ab 100644 (file)
@@ -6,7 +6,10 @@
 
 #include "content/browser/loader/resource_scheduler.h"
 
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
 #include "base/stl_util.h"
+#include "base/time/time.h"
 #include "content/common/resource_messages.h"
 #include "content/browser/loader/resource_message_delegate.h"
 #include "content/public/browser/resource_controller.h"
 
 namespace content {
 
+namespace {
+
+void PostHistogram(const char* base_name,
+                   const char* suffix,
+                   base::TimeDelta time) {
+  std::string histogram_name =
+      base::StringPrintf("ResourceScheduler.%s.%s", base_name, suffix);
+  base::HistogramBase* histogram_counter = base::Histogram::FactoryTimeGet(
+      histogram_name,
+      base::TimeDelta::FromMilliseconds(1),
+      base::TimeDelta::FromMinutes(5),
+      50,
+      base::Histogram::kUmaTargetedHistogramFlag);
+  histogram_counter->AddTime(time);
+}
+
+}  // namespace
+
 static const size_t kCoalescedTimerPeriod = 5000;
 static const size_t kMaxNumDelayableRequestsPerClient = 10;
 static const size_t kMaxNumDelayableRequestsPerHost = 6;
@@ -122,6 +143,7 @@ class ResourceScheduler::ScheduledResourceRequest
                            const RequestPriorityParams& priority)
       : ResourceMessageDelegate(request),
         client_id_(client_id),
+        client_state_on_creation_(scheduler->GetClientState(client_id_)),
         request_(request),
         ready_(false),
         deferred_(false),
@@ -133,17 +155,39 @@ class ResourceScheduler::ScheduledResourceRequest
                              "url", request->url().spec());
   }
 
-  virtual ~ScheduledResourceRequest() {
-    scheduler_->RemoveRequest(this);
-  }
+  ~ScheduledResourceRequest() override { scheduler_->RemoveRequest(this); }
 
   void Start() {
     TRACE_EVENT_ASYNC_STEP_PAST0("net", "URLRequest", request_, "Queued");
     ready_ = true;
-    if (deferred_ && request_->status().is_success()) {
+    if (!request_->status().is_success())
+      return;
+    base::TimeTicks time = base::TimeTicks::Now();
+    ClientState current_state = scheduler_->GetClientState(client_id_);
+    // Note: the client state isn't perfectly accurate since it won't capture
+    // tabs which have switched between active and background multiple times.
+    // Ex: A tab with the following transitions Active -> Background -> Active
+    // will be recorded as Active.
+    const char* client_state = "Other";
+    if (current_state == client_state_on_creation_ && current_state == ACTIVE) {
+      client_state = "Active";
+    } else if (current_state == client_state_on_creation_ &&
+               current_state == BACKGROUND) {
+      client_state = "Background";
+    }
+
+    base::TimeDelta time_was_deferred = base::TimeDelta::FromMicroseconds(0);
+    if (deferred_) {
       deferred_ = false;
       controller()->Resume();
+      time_was_deferred = time - time_deferred_;
     }
+    PostHistogram("RequestTimeDeferred", client_state, time_was_deferred);
+    PostHistogram(
+        "RequestTimeThrottled", client_state, time - request_->creation_time());
+    // TODO(aiolos): Remove one of the above histograms after gaining an
+    // understanding of the difference between them and which one is more
+    // interesting.
   }
 
   void set_request_priority_params(const RequestPriorityParams& priority) {
@@ -168,7 +212,7 @@ class ResourceScheduler::ScheduledResourceRequest
 
  private:
   // ResourceMessageDelegate interface:
-  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+  bool OnMessageReceived(const IPC::Message& message) override {
     bool handled = true;
     IPC_BEGIN_MESSAGE_MAP(ScheduledResourceRequest, message)
       IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority)
@@ -178,20 +222,20 @@ class ResourceScheduler::ScheduledResourceRequest
   }
 
   // ResourceThrottle interface:
-  virtual void WillStartRequest(bool* defer) OVERRIDE {
+  void WillStartRequest(bool* defer) override {
     deferred_ = *defer = !ready_;
+    time_deferred_ = base::TimeTicks::Now();
   }
 
-  virtual const char* GetNameForLogging() const OVERRIDE {
-    return "ResourceScheduler";
-  }
+  const char* GetNameForLogging() const override { return "ResourceScheduler"; }
 
   void DidChangePriority(int request_id, net::RequestPriority new_priority,
                          int intra_priority_value) {
     scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value);
   }
 
-  ClientId client_id_;
+  const ClientId client_id_;
+  const ResourceScheduler::ClientState client_state_on_creation_;
   net::URLRequest* request_;
   bool ready_;
   bool deferred_;
@@ -199,6 +243,7 @@ class ResourceScheduler::ScheduledResourceRequest
   ResourceScheduler* scheduler_;
   RequestPriorityParams priority_;
   uint32 fifo_ordering_;
+  base::TimeTicks time_deferred_;
 
   DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest);
 };
@@ -229,8 +274,10 @@ void ResourceScheduler::RequestQueue::Insert(
 // Each client represents a tab.
 class ResourceScheduler::Client {
  public:
-  explicit Client(ResourceScheduler* scheduler, bool is_visible)
-      : is_audible_(false),
+  explicit Client(ResourceScheduler* scheduler,
+                  bool is_visible,
+                  bool is_audible)
+      : is_audible_(is_audible),
         is_visible_(is_visible),
         is_loaded_(false),
         is_paused_(false),
@@ -508,11 +555,11 @@ class ResourceScheduler::Client {
     // If a request is already marked as layout-blocking make sure to keep the
     // classification across redirects unless the priority was lowered.
     if (request->classification() == LAYOUT_BLOCKING_REQUEST &&
-        request->url_request()->priority() >= net::LOW) {
+        request->url_request()->priority() > net::LOW) {
       return LAYOUT_BLOCKING_REQUEST;
     }
 
-    if (!has_body_ && request->url_request()->priority() >= net::LOW)
+    if (!has_body_ && request->url_request()->priority() > net::LOW)
       return LAYOUT_BLOCKING_REQUEST;
 
     if (request->url_request()->priority() < net::LOW) {
@@ -563,7 +610,8 @@ class ResourceScheduler::Client {
   //   * Higher priority requests (>= net::LOW).
   //
   // 4. Layout-blocking requests:
-  //   * High-priority requests initiated before the renderer has a <body>.
+  //   * High-priority requests (> net::LOW) initiated before the renderer has
+  //     a <body>.
   //
   // 5. Low priority requests
   //
@@ -574,7 +622,7 @@ class ResourceScheduler::Client {
   //     immediately.
   //   * Low priority requests are delayable.
   //   * Allow one delayable request to load at a time while layout-blocking
-  //     requests are loading.
+  //     requests are loading or the body tag has not yet been parsed.
   //   * If no high priority or layout-blocking requests are in flight, start
   //     loading delayable requests.
   //   * Never exceed 10 delayable requests in flight per client.
@@ -653,7 +701,7 @@ class ResourceScheduler::Client {
     bool have_immediate_requests_in_flight =
         in_flight_requests_.size() > in_flight_delayable_count_;
     if (have_immediate_requests_in_flight &&
-        total_layout_blocking_count_ != 0 &&
+        (!has_body_ || total_layout_blocking_count_ != 0) &&
         in_flight_delayable_count_ != 0) {
       return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
     }
@@ -721,6 +769,14 @@ ResourceScheduler::ResourceScheduler()
       coalesced_clients_(0),
       coalescing_timer_(new base::Timer(true /* retain_user_task */,
                                         true /* is_repeating */)) {
+  std::string throttling_trial_group =
+      base::FieldTrialList::FindFullName("RequestThrottlingAndCoalescing");
+  if (throttling_trial_group == "Throttle") {
+    should_throttle_ = true;
+  } else if (throttling_trial_group == "Coalesce") {
+    should_coalesce_ = true;
+    should_throttle_ = true;
+  }
 }
 
 ResourceScheduler::~ResourceScheduler() {
@@ -748,9 +804,11 @@ scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
     net::URLRequest* url_request) {
   DCHECK(CalledOnValidThread());
   ClientId client_id = MakeClientId(child_id, route_id);
-  scoped_ptr<ScheduledResourceRequest> request(
-      new ScheduledResourceRequest(client_id, url_request, this,
-          RequestPriorityParams(url_request->priority(), 0)));
+  scoped_ptr<ScheduledResourceRequest> request(new ScheduledResourceRequest(
+      client_id,
+      url_request,
+      this,
+      RequestPriorityParams(url_request->priority(), 0)));
 
   ClientMap::iterator it = client_map_.find(client_id);
   if (it == client_map_.end()) {
@@ -760,12 +818,12 @@ scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
     // 3. The tab is closed while a RequestResource IPC is in flight.
     unowned_requests_.insert(request.get());
     request->Start();
-    return request.PassAs<ResourceThrottle>();
+    return request.Pass();
   }
 
   Client* client = it->second;
   client->ScheduleRequest(url_request, request.get());
-  return request.PassAs<ResourceThrottle>();
+  return request.Pass();
 }
 
 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) {
@@ -786,12 +844,13 @@ void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) {
 
 void ResourceScheduler::OnClientCreated(int child_id,
                                         int route_id,
-                                        bool is_visible) {
+                                        bool is_visible,
+                                        bool is_audible) {
   DCHECK(CalledOnValidThread());
   ClientId client_id = MakeClientId(child_id, route_id);
   DCHECK(!ContainsKey(client_map_, client_id));
 
-  Client* client = new Client(this, is_visible);
+  Client* client = new Client(this, is_visible, is_audible);
   client_map_[client_id] = client;
 
   // TODO(aiolos): set Client visibility/audibility when signals are added
@@ -821,6 +880,14 @@ void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
   client_map_.erase(it);
 }
 
+void ResourceScheduler::OnLoadingStateChanged(int child_id,
+                                              int route_id,
+                                              bool is_loaded) {
+  Client* client = GetClient(child_id, route_id);
+  DCHECK(client);
+  client->OnLoadingStateChanged(is_loaded);
+}
+
 void ResourceScheduler::OnVisibilityChanged(int child_id,
                                             int route_id,
                                             bool is_visible) {
@@ -829,12 +896,13 @@ void ResourceScheduler::OnVisibilityChanged(int child_id,
   client->OnVisibilityChanged(is_visible);
 }
 
-void ResourceScheduler::OnLoadingStateChanged(int child_id,
-                                              int route_id,
-                                              bool is_loaded) {
+void ResourceScheduler::OnAudibilityChanged(int child_id,
+                                            int route_id,
+                                            bool is_audible) {
   Client* client = GetClient(child_id, route_id);
-  DCHECK(client);
-  client->OnLoadingStateChanged(is_loaded);
+  // We might get this call after the client has been deleted.
+  if (client)
+    client->OnAudibilityChanged(is_audible);
 }
 
 void ResourceScheduler::OnNavigate(int child_id, int route_id) {
@@ -880,14 +948,6 @@ void ResourceScheduler::OnReceivedSpdyProxiedHttpResponse(
   client->OnReceivedSpdyProxiedHttpResponse();
 }
 
-void ResourceScheduler::OnAudibilityChanged(int child_id,
-                                            int route_id,
-                                            bool is_audible) {
-  Client* client = GetClient(child_id, route_id);
-  DCHECK(client);
-  client->OnAudibilityChanged(is_audible);
-}
-
 bool ResourceScheduler::IsClientVisibleForTesting(int child_id, int route_id) {
   Client* client = GetClient(child_id, route_id);
   DCHECK(client);
@@ -990,6 +1050,14 @@ void ResourceScheduler::LoadCoalescedRequests() {
   }
 }
 
+ResourceScheduler::ClientState ResourceScheduler::GetClientState(
+    ClientId client_id) const {
+  ClientMap::const_iterator client_it = client_map_.find(client_id);
+  if (client_it == client_map_.end())
+    return UNKNOWN;
+  return client_it->second->is_active() ? ACTIVE : BACKGROUND;
+}
+
 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request,
                                             net::RequestPriority new_priority,
                                             int new_intra_priority_value) {