Skip to content

Commit

Permalink
LoadTiming implementation in net, part 1.
Browse files Browse the repository at this point in the history
Calculate connection timing information in ConnectJobs,
add store it in ClientSocketHandles.

BUG=77446
Review URL: https://codereview.chromium.org/11428150

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@175412 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
mmenke@chromium.org committed Jan 7, 2013
1 parent 7f39bb6 commit 034df0f
Show file tree
Hide file tree
Showing 16 changed files with 606 additions and 56 deletions.
22 changes: 22 additions & 0 deletions net/base/load_timing_info.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/load_timing_info.h"

#include "net/base/net_log.h"

namespace net {

LoadTimingInfo::ConnectTiming::ConnectTiming() {}

LoadTimingInfo::ConnectTiming::~ConnectTiming() {}

LoadTimingInfo::LoadTimingInfo() : socket_reused(false),
socket_log_id(NetLog::Source::kInvalidId) {
}

LoadTimingInfo::~LoadTimingInfo() {}

} // namespace net

109 changes: 109 additions & 0 deletions net/base/load_timing_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_BASE_LOAD_TIMING_INFO_H_
#define NET_BASE_LOAD_TIMING_INFO_H_

#include "base/basictypes.h"
#include "base/time.h"
#include "net/base/net_export.h"

namespace net {

// All events that do not apply to a request have null times. For non-HTTP
// requests, all times other than the request_start times are null.
//
// The general order for events is:
// request_start
// proxy_start
// proxy_end
// *dns_start
// *dns_end
// *connect_start
// *ssl_start
// *ssl_end
// *connect_end
// send_start
// send_end
// receive_headers_end
//
// Those times without an asterisk are computed by the URLRequest, or by objects
// it directly creates and always owns. Those with an asterisk are computed
// by the connection attempt itself. Since the connection attempt may be
// started before a URLRequest, the starred times may occur before, during, or
// after the request_start and proxy events.
struct NET_EXPORT LoadTimingInfo {
// Contains the LoadTimingInfo events related to establishing a connection.
// These are all set by ConnectJobs.
struct NET_EXPORT_PRIVATE ConnectTiming {
ConnectTiming();
~ConnectTiming();

// The time spent looking up the host's DNS address. Null for requests that
// used proxies to look up the DNS address. Also null for SOCKS4 proxies,
// since the DNS address is only looked up after the connection is
// established, which results in unexpected event ordering.
// TODO(mmenke): The SOCKS4 event ordering could be refactored to allow
// these times to be non-null.
base::TimeTicks dns_start;
base::TimeTicks dns_end;

// The time spent establishing the connection. Connect time includes proxy
// connect times (Though not proxy_resolve times), DNS lookup times, time
// spent waiting in certain queues, TCP, and SSL time.
// TODO(mmenke): For proxies, this includes time spent blocking on higher
// level socket pools. Fix this.
// TODO(mmenke): Retried connections to the same server should apparently
// be included in this time. Consider supporting that.
// Since the network stack has multiple notions of a "retry",
// handled at different levels, this may not be worth
// worrying about - backup jobs, reused socket failure,
// multiple round authentication.
base::TimeTicks connect_start;
base::TimeTicks connect_end;

// The time when the SSL handshake started / completed. For non-HTTPS
// requests these are null. These times are only for the SSL connection to
// the final destination server, not an SSL/SPDY proxy.
base::TimeTicks ssl_start;
base::TimeTicks ssl_end;
};

LoadTimingInfo();
~LoadTimingInfo();

// True if the socket was reused. When true, DNS, connect, and SSL times
// will all be null. When false, those times may be null, too, for non-HTTP
// requests, or when they don't apply to a request.
bool socket_reused;

// Unique socket ID, can be used to identify requests served by the same
// socket.
// TODO(mmenke): Do something reasonable for SPDY proxies.
uint32 socket_log_id;

// Start time as a base::Time, so times can be coverted into actual times.
// Other times are recorded as TimeTicks so they are not affected by clock
// changes.
base::Time request_start_time;

base::TimeTicks request_start;

// The time spent determing which proxy to use. Null when there is no PAC.
base::TimeTicks proxy_resolve_start;
base::TimeTicks proxy_resolve_end;

ConnectTiming connect_timing;

// The time that sending HTTP request started / ended.
base::TimeTicks send_start;
base::TimeTicks send_end;

// The time at which the end of the HTTP headers were received.
base::TimeTicks receive_headers_end;
};

} // namespace net

#endif // NET_BASE_LOAD_TIMING_INFO_H_
2 changes: 2 additions & 0 deletions net/net.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@
'base/load_flags_list.h',
'base/load_states.h',
'base/load_states_list.h',
'base/load_timing_info.cc',
'base/load_timing_info.h',
'base/mapped_host_resolver.cc',
'base/mapped_host_resolver.h',
'base/mime_sniffer.cc',
Expand Down
19 changes: 19 additions & 0 deletions net/socket/client_socket_handle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ void ClientSocketHandle::ResetInternal(bool cancel) {
idle_time_ = base::TimeDelta();
init_time_ = base::TimeTicks();
setup_time_ = base::TimeDelta();
connect_timing_ = LoadTimingInfo::ConnectTiming();
pool_id_ = -1;
}

Expand Down Expand Up @@ -103,6 +104,24 @@ void ClientSocketHandle::RemoveLayeredPool(LayeredPool* layered_pool) {
}
}

bool ClientSocketHandle::GetLoadTimingInfo(
bool is_reused,
LoadTimingInfo* load_timing_info) const {
// Only return load timing information when there's a socket.
if (!socket_)
return false;

load_timing_info->socket_log_id = socket_->NetLog().source().id;
load_timing_info->socket_reused = is_reused;

// No times if the socket is reused.
if (is_reused)
return true;

load_timing_info->connect_timing = connect_timing_;
return true;
}

void ClientSocketHandle::OnIOComplete(int result) {
CompletionCallback callback = user_callback_;
user_callback_.Reset();
Expand Down
18 changes: 18 additions & 0 deletions net/socket/client_socket_handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "base/time.h"
#include "net/base/completion_callback.h"
#include "net/base/load_states.h"
#include "net/base/load_timing_info.h"
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
#include "net/base/net_log.h"
Expand Down Expand Up @@ -106,6 +107,14 @@ class NET_EXPORT ClientSocketHandle {
// Returns the time between Init() and when is_initialized() becomes true.
base::TimeDelta setup_time() const { return setup_time_; }

// Sets the portion of LoadTimingInfo related to connection establishment, and
// the socket id. |is_reused| is needed because the handle may not have full
// reuse information. |load_timing_info| must have all default values when
// called. Returns false and makes no changes to |load_timing_info| when
// |socket_| is NULL.
bool GetLoadTimingInfo(bool is_reused,
LoadTimingInfo* load_timing_info) const;

// Used by ClientSocketPool to initialize the ClientSocketHandle.
void set_is_reused(bool is_reused) { is_reused_ = is_reused; }
void set_socket(StreamSocket* s) { socket_.reset(s); }
Expand Down Expand Up @@ -150,6 +159,12 @@ class NET_EXPORT ClientSocketHandle {
return UNUSED_IDLE;
}
}
const LoadTimingInfo::ConnectTiming& connect_timing() const {
return connect_timing_;
}
void set_connect_timing(const LoadTimingInfo::ConnectTiming& connect_timing) {
connect_timing_ = connect_timing;
}

private:
// Called on asynchronous completion of an Init() request.
Expand Down Expand Up @@ -185,6 +200,9 @@ class NET_EXPORT ClientSocketHandle {

NetLog::Source requesting_source_;

// Timing information is set when a connection is successfully established.
LoadTimingInfo::ConnectTiming connect_timing_;

DISALLOW_COPY_AND_ASSIGN(ClientSocketHandle);
};

Expand Down
28 changes: 19 additions & 9 deletions net/socket/client_socket_pool_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,12 @@ void ConnectJob::ResetTimer(base::TimeDelta remaining_time) {
}

void ConnectJob::LogConnectStart() {
connect_timing_.connect_start = base::TimeTicks::Now();
net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT);
}

void ConnectJob::LogConnectCompletion(int net_error) {
connect_timing_.connect_end = base::TimeTicks::Now();
net_log().EndEventWithNetErrorCode(
NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT, net_error);
}
Expand Down Expand Up @@ -383,7 +385,8 @@ int ClientSocketPoolBaseHelper::RequestSocketInternal(
LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
if (!preconnecting) {
HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
handle, base::TimeDelta(), group, request->net_log());
connect_job->connect_timing(), handle, base::TimeDelta(),
group, request->net_log());
} else {
AddIdleSocket(connect_job->ReleaseSocket(), group);
}
Expand All @@ -408,8 +411,9 @@ int ClientSocketPoolBaseHelper::RequestSocketInternal(
error_socket = connect_job->ReleaseSocket();
}
if (error_socket) {
HandOutSocket(error_socket, false /* not reused */, handle,
base::TimeDelta(), group, request->net_log());
HandOutSocket(error_socket, false /* not reused */,
connect_job->connect_timing(), handle, base::TimeDelta(),
group, request->net_log());
} else if (group->IsEmpty()) {
RemoveGroup(group_name);
}
Expand Down Expand Up @@ -475,6 +479,7 @@ bool ClientSocketPoolBaseHelper::AssignIdleSocketToRequest(
HandOutSocket(
idle_socket.socket,
idle_socket.socket->WasEverUsed(),
LoadTimingInfo::ConnectTiming(),
request->handle(),
idle_time,
group,
Expand Down Expand Up @@ -855,7 +860,10 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete(

scoped_ptr<StreamSocket> socket(job->ReleaseSocket());

// Copies of these are needed because |job| may be deleted before they are
// accessed.
BoundNetLog job_log = job->net_log();
LoadTimingInfo::ConnectTiming connect_timing = job->connect_timing();

if (result == OK) {
DCHECK(socket.get());
Expand All @@ -865,8 +873,8 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete(
group->mutable_pending_requests()->begin(), group));
LogBoundConnectJobToRequest(job_log.source(), r.get());
HandOutSocket(
socket.release(), false /* unused socket */, r->handle(),
base::TimeDelta(), group, r->net_log());
socket.release(), false /* unused socket */, connect_timing,
r->handle(), base::TimeDelta(), group, r->net_log());
r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL);
InvokeUserCallbackLater(r->handle(), r->callback(), result);
} else {
Expand All @@ -886,11 +894,11 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete(
RemoveConnectJob(job, group);
if (socket.get()) {
handed_out_socket = true;
HandOutSocket(socket.release(), false /* unused socket */, r->handle(),
base::TimeDelta(), group, r->net_log());
HandOutSocket(socket.release(), false /* unused socket */,
connect_timing, r->handle(), base::TimeDelta(), group,
r->net_log());
}
r->net_log().EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL,
result);
r->net_log().EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL, result);
InvokeUserCallbackLater(r->handle(), r->callback(), result);
} else {
RemoveConnectJob(job, group);
Expand Down Expand Up @@ -977,6 +985,7 @@ void ClientSocketPoolBaseHelper::ProcessPendingRequest(
void ClientSocketPoolBaseHelper::HandOutSocket(
StreamSocket* socket,
bool reused,
const LoadTimingInfo::ConnectTiming& connect_timing,
ClientSocketHandle* handle,
base::TimeDelta idle_time,
Group* group,
Expand All @@ -986,6 +995,7 @@ void ClientSocketPoolBaseHelper::HandOutSocket(
handle->set_is_reused(reused);
handle->set_idle_time(idle_time);
handle->set_pool_id(pool_generation_number_);
handle->set_connect_timing(connect_timing);

if (reused) {
net_log.AddEvent(
Expand Down
9 changes: 9 additions & 0 deletions net/socket/client_socket_pool_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
#include "net/base/load_states.h"
#include "net/base/load_timing_info.h"
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
#include "net/base/net_log.h"
Expand Down Expand Up @@ -104,6 +105,10 @@ class NET_EXPORT_PRIVATE ConnectJob {
// additional error state to the ClientSocketHandle (post late-binding).
virtual void GetAdditionalErrorState(ClientSocketHandle* handle) {}

const LoadTimingInfo::ConnectTiming& connect_timing() const {
return connect_timing_;
}

const BoundNetLog& net_log() const { return net_log_; }

protected:
Expand All @@ -112,6 +117,9 @@ class NET_EXPORT_PRIVATE ConnectJob {
void NotifyDelegateOfCompletion(int rv);
void ResetTimer(base::TimeDelta remainingTime);

// Connection establishment timing information.
LoadTimingInfo::ConnectTiming connect_timing_;

private:
virtual int ConnectInternal() = 0;

Expand Down Expand Up @@ -493,6 +501,7 @@ class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper
// Assigns |socket| to |handle| and updates |group|'s counters appropriately.
void HandOutSocket(StreamSocket* socket,
bool reused,
const LoadTimingInfo::ConnectTiming& connect_timing,
ClientSocketHandle* handle,
base::TimeDelta time_idle,
Group* group,
Expand Down
Loading

0 comments on commit 034df0f

Please sign in to comment.