| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "net/base/file_stream.h" |
| 6 |
| 7 #include <string> |
| 8 #if defined(OS_WIN) |
| 9 #include <windows.h> |
| 10 #endif |
| 11 |
| 12 #include "base/basictypes.h" |
| 13 #include "base/logging.h" |
| 14 #include "base/metrics/histogram.h" |
| 15 |
| 16 namespace net { |
| 17 |
| 18 namespace { |
| 19 |
| 20 int g_recording_class_mask = RECORDING_CLASS_NONE; |
| 21 |
| 22 #if defined(OS_WIN) |
| 23 |
| 24 struct Range { |
| 25 int low; |
| 26 int high; |
| 27 bool record_individually; |
| 28 }; |
| 29 |
| 30 // This must be higher than the largest value that isn't remapped into a bucket. |
| 31 int kErrorBucketStart = 400; |
| 32 |
| 33 Range kErrorRangeList[] = { |
| 34 { 0, 321, true }, // These are the ones we don't remap into buckets. |
| 35 { 335, 371, false }, |
| 36 { 383, 387, false }, |
| 37 { 399, 404, false }, |
| 38 { 415, 418, false }, |
| 39 { 431, 433, false }, |
| 40 { 447, 868, false }, |
| 41 { 994, 1471, false }, |
| 42 { 1500, 1513, false }, |
| 43 { 1536, 1553, false }, |
| 44 { 1601, 1654, false }, |
| 45 { 1700, 1834, false }, |
| 46 { 1898, 1938, false }, |
| 47 { 2000, 2024, false }, |
| 48 { 2048, 2085, false }, |
| 49 { 2108, 2110, false }, |
| 50 { 2202, 2203, false }, |
| 51 { 2250, 2251, false }, |
| 52 { 2401, 2405, false }, |
| 53 { 3000, 3021, false }, |
| 54 { 3950, 3951, false }, |
| 55 { 4000, 4007, false }, |
| 56 { 4050, 4066, false }, |
| 57 { 4096, 4116, false }, |
| 58 { 4200, 4215, false }, |
| 59 { 4300, 4353, false }, |
| 60 { 4390, 4395, false }, |
| 61 { 4500, 4501, false }, |
| 62 { 4864, 4905, false }, |
| 63 { 5001, 5090, false }, |
| 64 { 5890, 5953, false }, |
| 65 { 6000, 6023, false }, |
| 66 { 6118, 6119, false }, |
| 67 { 6200, 6201, false }, |
| 68 { 6600, 6649, false }, |
| 69 { 6700, 6732, false }, |
| 70 { 6800, 6856, false }, |
| 71 { 7001, 7071, false }, |
| 72 { 8001, 8018, false }, |
| 73 { 8192, 8263, false }, |
| 74 { 8301, 8640, false }, |
| 75 { 8704, 8705, false }, |
| 76 { 8960, 9053, false }, |
| 77 { 9216, 9218, false }, |
| 78 { 9263, 9276, false }, |
| 79 { 9472, 9506, false }, |
| 80 { 9550, 9573, false }, |
| 81 { 9600, 9622, false }, |
| 82 { 9650, 9656, false }, |
| 83 { 9688, 9723, false }, |
| 84 { 9750, 9754, false }, |
| 85 { 9800, 9802, false }, |
| 86 { 9850, 9853, false }, |
| 87 { 9900, 9907, false }, |
| 88 { 10000, 10072, false }, |
| 89 { 10091, 10113, false }, |
| 90 { 11001, 11034, false }, |
| 91 { 12288, 12335, false }, |
| 92 { 12544, 12559, false }, |
| 93 { 12595, 12597, false }, |
| 94 { 12801, 12803, false }, |
| 95 { 13000, 13026, false }, |
| 96 { 13800, 13933, false }, |
| 97 { 14000, 14111, false }, |
| 98 { 15000, 15039, false }, |
| 99 { 15080, 15086, false }, |
| 100 { 15100, 15109, false }, |
| 101 { 15200, 15208, false }, |
| 102 { 15250, 15251, false }, |
| 103 { 15299, 15302, false }, |
| 104 { 16385, 16436, false }, |
| 105 { 18432, 18454, false }, |
| 106 { 20480, 20486, false }, |
| 107 { 24577, 24607, false }, |
| 108 { 28673, 28698, false }, |
| 109 { 32790, 32816, false }, |
| 110 { 33281, 33322, false }, |
| 111 { 35005, 35024, false }, |
| 112 { 36000, 36004, false }, |
| 113 { 40010, 40011, false }, |
| 114 { 40067, 40069, false }, |
| 115 { 53248, 53293, false }, |
| 116 { 53376, 53382, false }, |
| 117 { 57344, 57360, false }, |
| 118 { 57377, 57394, false }, |
| 119 { 65535, 65536 } |
| 120 }; |
| 121 size_t kNumErrorRanges = ARRAYSIZE_UNSAFE(kErrorRangeList); |
| 122 |
| 123 // Windows has very many errors. We're not interested in most of them, but we |
| 124 // don't know which ones are significant. |
| 125 // This function maps error ranges we think we don't care about to specific |
| 126 // buckets, and leaves the others alone. If we get hits on the buckets, |
| 127 // we can add those values to the values we leave alone. |
| 128 // If we get values *between* the buckets, we record those as buckets too. |
| 129 // The range list is extracted from WinError.h. |
| 130 int ReduceErrorRange(int error) { |
| 131 error = HRESULT_CODE(error); |
| 132 |
| 133 for (size_t n = 0; n < kNumErrorRanges; ++n) { |
| 134 if (kErrorRangeList[n].record_individually) { |
| 135 if (error < kErrorRangeList[n].low) |
| 136 return kErrorBucketStart + (2 * n) - 1; // In gap before the bucket. |
| 137 if (error <= kErrorRangeList[n].high) |
| 138 return error; // Record individually. |
| 139 } else { |
| 140 if (error < kErrorRangeList[n].low) |
| 141 return kErrorBucketStart + (2 * n) - 1; // In gap before the bucket. |
| 142 if (error <= kErrorRangeList[n].high) |
| 143 return kErrorBucketStart + 2 * n; // In bucket. |
| 144 } |
| 145 } |
| 146 |
| 147 // After the last bucket. |
| 148 return kErrorBucketStart + 2 * kNumErrorRanges; |
| 149 } |
| 150 |
| 151 #endif // defined(OS_WIN) |
| 152 |
| 153 void RecordFileErrorTypeCount(FileErrorTypes type) { |
| 154 UMA_HISTOGRAM_ENUMERATION( |
| 155 "FileErrorType.Counts", type, FILE_ERROR_TYPES_COUNT); |
| 156 } |
| 157 |
| 158 std::string RecordUmaName(FileErrorTypes type, int class_flags) { |
| 159 std::string s; |
| 160 static const char* names[] = { |
| 161 "FileErrorTypes.NotOpenError", |
| 162 "FileErrorTypes.OpenError", |
| 163 "FileErrorTypes.WriteError", |
| 164 "FileErrorTypes.ReadError", |
| 165 "FileErrorTypes.SeekError", |
| 166 "FileErrorTypes.FlushError", |
| 167 "FileErrorTypes.SetEofError", |
| 168 "FileErrorTypes.GetSizeError", |
| 169 }; |
| 170 static const char* classes[] = { |
| 171 ".Download", |
| 172 // Add more strings here as necessary to match |RecordingClass| items. |
| 173 }; |
| 174 static const int num_classes = ARRAYSIZE_UNSAFE(classes); |
| 175 |
| 176 s = names[type]; |
| 177 |
| 178 int i; |
| 179 int mask; |
| 180 int start = RECORDING_CLASS_NONE + 1; |
| 181 for (i = start, mask = 1 << (start - 1); |
| 182 i < (num_classes + start); |
| 183 mask <<= 1, i++) { |
| 184 if (class_flags & mask) { |
| 185 s += classes[i - start]; |
| 186 break; |
| 187 } |
| 188 } |
| 189 |
| 190 return s; |
| 191 } |
| 192 |
| 193 } // namespace |
| 194 |
| 195 void EnableRecordingForClass(int class_flags) { |
| 196 g_recording_class_mask = class_flags; |
| 197 } |
| 198 |
| 199 #define UMA_HISTOGRAM_CLASS(c) \ |
| 200 if (class_flags & (1 << RECORDING_CLASS_##c) & g_recording_class_mask) { \ |
| 201 UMA_HISTOGRAM_ENUMERATION(name.c_str(), error, max_error); \ |
| 202 break; \ |
| 203 } |
| 204 |
| 205 #define UMA_HISTOGRAM_CLASSES() \ |
| 206 for (int i = 0; i < RECORDING_CLASS_MAX; ++i) { \ |
| 207 UMA_HISTOGRAM_CLASS(DOWNLOADS) \ |
| 208 } |
| 209 |
| 210 #define UMA_HISTOGRAM_TYPE(t) \ |
| 211 case FILE_ERROR_TYPES_##t: \ |
| 212 UMA_HISTOGRAM_CLASSES() \ |
| 213 break; |
| 214 |
| 215 void RecordFileError(int error, FileErrorTypes type, int class_flags) { |
| 216 if (class_flags == RECORDING_CLASS_NONE) |
| 217 return; |
| 218 |
| 219 RecordFileErrorTypeCount(type); |
| 220 |
| 221 std::string name = RecordUmaName(type, class_flags); |
| 222 |
| 223 DLOG(WARNING) << "() " << "Recording error " << error |
| 224 << " of type " << type << " with flags " << class_flags |
| 225 << ". Name = '" << name << "'"; |
| 226 |
| 227 unsigned int max_error = (1U << 14) - 2; // Histogram limit. |
| 228 |
| 229 #if defined(OS_WIN) |
| 230 error = ReduceErrorRange(error); |
| 231 max_error = kErrorBucketStart + 2 * kNumErrorRanges + 1; |
| 232 #elif defined(OS_POSIX) |
| 233 // Posix errors seem to have only low positive values. |
| 234 max_error = 160; |
| 235 #endif |
| 236 |
| 237 switch(type) { |
| 238 UMA_HISTOGRAM_TYPE(IS_NOT_OPEN) |
| 239 UMA_HISTOGRAM_TYPE(OPEN) |
| 240 UMA_HISTOGRAM_TYPE(WRITE) |
| 241 UMA_HISTOGRAM_TYPE(READ) |
| 242 UMA_HISTOGRAM_TYPE(SEEK) |
| 243 UMA_HISTOGRAM_TYPE(FLUSH) |
| 244 UMA_HISTOGRAM_TYPE(SET_EOF) |
| 245 UMA_HISTOGRAM_TYPE(GET_SIZE) |
| 246 default: |
| 247 break; |
| 248 } |
| 249 } |
| 250 |
| 251 } // namespace net |
| OLD | NEW |