| Index: net/base/file_stream.cc
|
| diff --git a/net/base/file_stream.cc b/net/base/file_stream.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..aae50c2d14ccb092f72b05fcbb4f8c61d776a44c
|
| --- /dev/null
|
| +++ b/net/base/file_stream.cc
|
| @@ -0,0 +1,251 @@
|
| +// Copyright (c) 2011 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/file_stream.h"
|
| +
|
| +#include <string>
|
| +#if defined(OS_WIN)
|
| +#include <windows.h>
|
| +#endif
|
| +
|
| +#include "base/basictypes.h"
|
| +#include "base/logging.h"
|
| +#include "base/metrics/histogram.h"
|
| +
|
| +namespace net {
|
| +
|
| +namespace {
|
| +
|
| +int g_recording_class_mask = RECORDING_CLASS_NONE;
|
| +
|
| +#if defined(OS_WIN)
|
| +
|
| +struct Range {
|
| + int low;
|
| + int high;
|
| + bool record_individually;
|
| +};
|
| +
|
| +// This must be higher than the largest value that isn't remapped into a bucket.
|
| +int kErrorBucketStart = 400;
|
| +
|
| +Range kErrorRangeList[] = {
|
| + { 0, 321, true }, // These are the ones we don't remap into buckets.
|
| + { 335, 371, false },
|
| + { 383, 387, false },
|
| + { 399, 404, false },
|
| + { 415, 418, false },
|
| + { 431, 433, false },
|
| + { 447, 868, false },
|
| + { 994, 1471, false },
|
| + { 1500, 1513, false },
|
| + { 1536, 1553, false },
|
| + { 1601, 1654, false },
|
| + { 1700, 1834, false },
|
| + { 1898, 1938, false },
|
| + { 2000, 2024, false },
|
| + { 2048, 2085, false },
|
| + { 2108, 2110, false },
|
| + { 2202, 2203, false },
|
| + { 2250, 2251, false },
|
| + { 2401, 2405, false },
|
| + { 3000, 3021, false },
|
| + { 3950, 3951, false },
|
| + { 4000, 4007, false },
|
| + { 4050, 4066, false },
|
| + { 4096, 4116, false },
|
| + { 4200, 4215, false },
|
| + { 4300, 4353, false },
|
| + { 4390, 4395, false },
|
| + { 4500, 4501, false },
|
| + { 4864, 4905, false },
|
| + { 5001, 5090, false },
|
| + { 5890, 5953, false },
|
| + { 6000, 6023, false },
|
| + { 6118, 6119, false },
|
| + { 6200, 6201, false },
|
| + { 6600, 6649, false },
|
| + { 6700, 6732, false },
|
| + { 6800, 6856, false },
|
| + { 7001, 7071, false },
|
| + { 8001, 8018, false },
|
| + { 8192, 8263, false },
|
| + { 8301, 8640, false },
|
| + { 8704, 8705, false },
|
| + { 8960, 9053, false },
|
| + { 9216, 9218, false },
|
| + { 9263, 9276, false },
|
| + { 9472, 9506, false },
|
| + { 9550, 9573, false },
|
| + { 9600, 9622, false },
|
| + { 9650, 9656, false },
|
| + { 9688, 9723, false },
|
| + { 9750, 9754, false },
|
| + { 9800, 9802, false },
|
| + { 9850, 9853, false },
|
| + { 9900, 9907, false },
|
| + { 10000, 10072, false },
|
| + { 10091, 10113, false },
|
| + { 11001, 11034, false },
|
| + { 12288, 12335, false },
|
| + { 12544, 12559, false },
|
| + { 12595, 12597, false },
|
| + { 12801, 12803, false },
|
| + { 13000, 13026, false },
|
| + { 13800, 13933, false },
|
| + { 14000, 14111, false },
|
| + { 15000, 15039, false },
|
| + { 15080, 15086, false },
|
| + { 15100, 15109, false },
|
| + { 15200, 15208, false },
|
| + { 15250, 15251, false },
|
| + { 15299, 15302, false },
|
| + { 16385, 16436, false },
|
| + { 18432, 18454, false },
|
| + { 20480, 20486, false },
|
| + { 24577, 24607, false },
|
| + { 28673, 28698, false },
|
| + { 32790, 32816, false },
|
| + { 33281, 33322, false },
|
| + { 35005, 35024, false },
|
| + { 36000, 36004, false },
|
| + { 40010, 40011, false },
|
| + { 40067, 40069, false },
|
| + { 53248, 53293, false },
|
| + { 53376, 53382, false },
|
| + { 57344, 57360, false },
|
| + { 57377, 57394, false },
|
| + { 65535, 65536 }
|
| +};
|
| +size_t kNumErrorRanges = ARRAYSIZE_UNSAFE(kErrorRangeList);
|
| +
|
| +// Windows has very many errors. We're not interested in most of them, but we
|
| +// don't know which ones are significant.
|
| +// This function maps error ranges we think we don't care about to specific
|
| +// buckets, and leaves the others alone. If we get hits on the buckets,
|
| +// we can add those values to the values we leave alone.
|
| +// If we get values *between* the buckets, we record those as buckets too.
|
| +// The range list is extracted from WinError.h.
|
| +int ReduceErrorRange(int error) {
|
| + error = HRESULT_CODE(error);
|
| +
|
| + for (size_t n = 0; n < kNumErrorRanges; ++n) {
|
| + if (kErrorRangeList[n].record_individually) {
|
| + if (error < kErrorRangeList[n].low)
|
| + return kErrorBucketStart + (2 * n) - 1; // In gap before the bucket.
|
| + if (error <= kErrorRangeList[n].high)
|
| + return error; // Record individually.
|
| + } else {
|
| + if (error < kErrorRangeList[n].low)
|
| + return kErrorBucketStart + (2 * n) - 1; // In gap before the bucket.
|
| + if (error <= kErrorRangeList[n].high)
|
| + return kErrorBucketStart + 2 * n; // In bucket.
|
| + }
|
| + }
|
| +
|
| + // After the last bucket.
|
| + return kErrorBucketStart + 2 * kNumErrorRanges;
|
| +}
|
| +
|
| +#endif // defined(OS_WIN)
|
| +
|
| +void RecordFileErrorTypeCount(FileErrorTypes type) {
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + "FileErrorType.Counts", type, FILE_ERROR_TYPES_COUNT);
|
| +}
|
| +
|
| +std::string RecordUmaName(FileErrorTypes type, int class_flags) {
|
| + std::string s;
|
| + static const char* names[] = {
|
| + "FileErrorTypes.NotOpenError",
|
| + "FileErrorTypes.OpenError",
|
| + "FileErrorTypes.WriteError",
|
| + "FileErrorTypes.ReadError",
|
| + "FileErrorTypes.SeekError",
|
| + "FileErrorTypes.FlushError",
|
| + "FileErrorTypes.SetEofError",
|
| + "FileErrorTypes.GetSizeError",
|
| + };
|
| + static const char* classes[] = {
|
| + ".Download",
|
| + // Add more strings here as necessary to match |RecordingClass| items.
|
| + };
|
| + static const int num_classes = ARRAYSIZE_UNSAFE(classes);
|
| +
|
| + s = names[type];
|
| +
|
| + int i;
|
| + int mask;
|
| + int start = RECORDING_CLASS_NONE + 1;
|
| + for (i = start, mask = 1 << (start - 1);
|
| + i < (num_classes + start);
|
| + mask <<= 1, i++) {
|
| + if (class_flags & mask) {
|
| + s += classes[i - start];
|
| + break;
|
| + }
|
| + }
|
| +
|
| + return s;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +void EnableRecordingForClass(int class_flags) {
|
| + g_recording_class_mask = class_flags;
|
| +}
|
| +
|
| +#define UMA_HISTOGRAM_CLASS(c) \
|
| + if (class_flags & (1 << RECORDING_CLASS_##c) & g_recording_class_mask) { \
|
| + UMA_HISTOGRAM_ENUMERATION(name.c_str(), error, max_error); \
|
| + break; \
|
| + }
|
| +
|
| +#define UMA_HISTOGRAM_CLASSES() \
|
| + for (int i = 0; i < RECORDING_CLASS_MAX; ++i) { \
|
| + UMA_HISTOGRAM_CLASS(DOWNLOADS) \
|
| + }
|
| +
|
| +#define UMA_HISTOGRAM_TYPE(t) \
|
| + case FILE_ERROR_TYPES_##t: \
|
| + UMA_HISTOGRAM_CLASSES() \
|
| + break;
|
| +
|
| +void RecordFileError(int error, FileErrorTypes type, int class_flags) {
|
| + if (class_flags == RECORDING_CLASS_NONE)
|
| + return;
|
| +
|
| + RecordFileErrorTypeCount(type);
|
| +
|
| + std::string name = RecordUmaName(type, class_flags);
|
| +
|
| + DLOG(WARNING) << "() " << "Recording error " << error
|
| + << " of type " << type << " with flags " << class_flags
|
| + << ". Name = '" << name << "'";
|
| +
|
| + unsigned int max_error = (1U << 14) - 2; // Histogram limit.
|
| +
|
| +#if defined(OS_WIN)
|
| + error = ReduceErrorRange(error);
|
| + max_error = kErrorBucketStart + 2 * kNumErrorRanges + 1;
|
| +#elif defined(OS_POSIX)
|
| + // Posix errors seem to have only low positive values.
|
| + max_error = 160;
|
| +#endif
|
| +
|
| + switch(type) {
|
| + UMA_HISTOGRAM_TYPE(IS_NOT_OPEN)
|
| + UMA_HISTOGRAM_TYPE(OPEN)
|
| + UMA_HISTOGRAM_TYPE(WRITE)
|
| + UMA_HISTOGRAM_TYPE(READ)
|
| + UMA_HISTOGRAM_TYPE(SEEK)
|
| + UMA_HISTOGRAM_TYPE(FLUSH)
|
| + UMA_HISTOGRAM_TYPE(SET_EOF)
|
| + UMA_HISTOGRAM_TYPE(GET_SIZE)
|
| + default:
|
| + break;
|
| + }
|
| +}
|
| +
|
| +} // namespace net
|
|
|