summaryrefslogtreecommitdiffstats
path: root/net/socket/client_socket.cc
blob: 6b12841ee842238544fee8720e72b94360f4ce50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Copyright (c) 2010 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/socket/client_socket.h"

#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/string_number_conversions.h"
#include "base/values.h"

namespace net {

namespace {

// Parameters for SOCKET_BYTES_RECEIVED and SOCKET_BYTES_SENT events.
// Includes bytes transferred and, if |bytes| is not NULL, the bytes themselves.
class NetLogBytesTransferredParameter : public NetLog::EventParameters {
 public:
  NetLogBytesTransferredParameter(int byte_count, const char* bytes);

  virtual Value* ToValue() const;

 private:
  const int byte_count_;
  std::string hex_encoded_bytes_;
  bool has_bytes_;
};

NetLogBytesTransferredParameter::NetLogBytesTransferredParameter(
    int byte_count, const char* transferred_bytes)
    : byte_count_(byte_count),
      has_bytes_(false) {
  if (transferred_bytes) {
    hex_encoded_bytes_ = base::HexEncode(transferred_bytes, byte_count);
    has_bytes_ = true;
  }
}

Value* NetLogBytesTransferredParameter::ToValue() const {
  DictionaryValue* dict = new DictionaryValue();
  dict->SetInteger("byte_count", byte_count_);
  if (has_bytes_)
    dict->SetString("hex_encoded_bytes", hex_encoded_bytes_);
  return dict;
}

}  // namespace

ClientSocket::UseHistory::UseHistory()
    : was_ever_connected_(false),
      was_used_to_convey_data_(false),
      omnibox_speculation_(false),
      subresource_speculation_(false) {
}

ClientSocket::UseHistory::~UseHistory() {
  EmitPreconnectionHistograms();
}

void ClientSocket::UseHistory::Reset() {
  EmitPreconnectionHistograms();
  was_ever_connected_ = false;
  was_used_to_convey_data_ = false;
  // omnibox_speculation_ and subresource_speculation_ values
  // are intentionally preserved.
}

void ClientSocket::UseHistory::EmitPreconnectionHistograms() const {
  DCHECK(!subresource_speculation_ || !omnibox_speculation_);
  // 0 ==> non-speculative, never connected.
  // 1 ==> non-speculative never used (but connected).
  // 2 ==> non-speculative and used.
  // 3 ==> omnibox_speculative never connected.
  // 4 ==> omnibox_speculative never used (but connected).
  // 5 ==> omnibox_speculative and used.
  // 6 ==> subresource_speculative never connected.
  // 7 ==> subresource_speculative never used (but connected).
  // 8 ==> subresource_speculative and used.
  int result;
  if (was_used_to_convey_data_)
    result = 2;
  else if (was_ever_connected_)
    result = 1;
  else
    result = 0;  // Never used, and not really connected.

  if (omnibox_speculation_)
    result += 3;
  else if (subresource_speculation_)
    result += 6;
  UMA_HISTOGRAM_ENUMERATION("Net.PreconnectUtilization2", result, 9);

  static const bool connect_backup_jobs_fieldtrial =
      base::FieldTrialList::Find("ConnnectBackupJobs") &&
      !base::FieldTrialList::Find("ConnnectBackupJobs")->group_name().empty();
  if (connect_backup_jobs_fieldtrial) {
    UMA_HISTOGRAM_ENUMERATION(
        base::FieldTrial::MakeName("Net.PreconnectUtilization2",
                                   "ConnnectBackupJobs"),
        result, 9);
  }
}

void ClientSocket::UseHistory::set_was_ever_connected() {
  DCHECK(!was_used_to_convey_data_);
  was_ever_connected_ = true;
}

void ClientSocket::UseHistory::set_was_used_to_convey_data() {
  DCHECK(was_ever_connected_);
  was_used_to_convey_data_ = true;
}


void ClientSocket::UseHistory::set_subresource_speculation() {
  DCHECK(was_ever_connected_);
  // TODO(jar): We should transition to marking a socket (or stream) at
  // construction time as being created for speculative reasons.  This current
  // approach of trying to track use of a socket to convey data can make
  // mistakes when other sockets (such as ones sitting in the pool for a long
  // time) are issued.  Unused sockets can be left over when a when a set of
  // connections to a host are made, and one is "unlucky" and takes so long to
  // complete a connection, that another socket is used, and recycled before a
  // second connection comes available.  Similarly, re-try connections can leave
  // an original (slow to connect socket) in the pool, and that can be issued
  // to a speculative requester. In any cases such old sockets will fail when an
  // attempt is made to used them!... and then it will look like a speculative
  // socket was discarded without any user!?!?!
  if (was_used_to_convey_data_)
    return;
  subresource_speculation_ = true;
}

void ClientSocket::UseHistory::set_omnibox_speculation() {
  DCHECK(was_ever_connected_);
  if (was_used_to_convey_data_)
    return;
  omnibox_speculation_ = true;
}

bool ClientSocket::UseHistory::was_used_to_convey_data() const {
  DCHECK(!was_used_to_convey_data_ || was_ever_connected_);
  return was_used_to_convey_data_;
}

void ClientSocket::LogByteTransfer(const BoundNetLog& net_log,
                                   NetLog::EventType event_type,
                                   int byte_count,
                                   char* bytes) const {
  scoped_refptr<NetLog::EventParameters> params;
  if (net_log.IsLoggingBytes()) {
    params = new NetLogBytesTransferredParameter(byte_count, bytes);
  } else {
    params = new NetLogBytesTransferredParameter(byte_count, NULL);
  }
  net_log.AddEvent(event_type, params);
}

}  // namespace net