diff options
author | ahendrickson@chromium.org <ahendrickson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-23 20:38:20 +0000 |
---|---|---|
committer | ahendrickson@chromium.org <ahendrickson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-23 20:38:20 +0000 |
commit | 210564f22a7eeacb57b9fe62f254cda5c2e6722b (patch) | |
tree | b62db0d21d520d79a9d5f45c900a6c44337b4757 /net | |
parent | 71751eb28961e96a0cbf4d91f02610329f1c87ce (diff) | |
download | chromium_src-210564f22a7eeacb57b9fe62f254cda5c2e6722b.zip chromium_src-210564f22a7eeacb57b9fe62f254cda5c2e6722b.tar.gz chromium_src-210564f22a7eeacb57b9fe62f254cda5c2e6722b.tar.bz2 |
Record UMA statistics for file_stream operations.
Allows control over whether or not to record the statistics based on flags.
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/7583049
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@102560 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/file_stream.h | 4 | ||||
-rw-r--r-- | net/base/file_stream_metrics.cc | 81 | ||||
-rw-r--r-- | net/base/file_stream_metrics.h | 41 | ||||
-rw-r--r-- | net/base/file_stream_metrics_posix.cc | 21 | ||||
-rw-r--r-- | net/base/file_stream_metrics_win.cc | 146 | ||||
-rw-r--r-- | net/base/file_stream_posix.cc | 74 | ||||
-rw-r--r-- | net/base/file_stream_win.cc | 66 | ||||
-rw-r--r-- | net/base/net_errors_posix.cc | 9 | ||||
-rw-r--r-- | net/base/net_errors_win.cc | 3 | ||||
-rw-r--r-- | net/net.gyp | 4 |
10 files changed, 410 insertions, 39 deletions
diff --git a/net/base/file_stream.h b/net/base/file_stream.h index a58557c..0a800b4 100644 --- a/net/base/file_stream.h +++ b/net/base/file_stream.h @@ -132,6 +132,9 @@ class NET_EXPORT FileStream { // This method should not be called if the stream was opened READ_ONLY. virtual int Flush(); + // Turns on UMA error statistics gathering. + void EnableErrorStatistics(); + private: class AsyncContext; friend class AsyncContext; @@ -143,6 +146,7 @@ class NET_EXPORT FileStream { base::PlatformFile file_; int open_flags_; bool auto_closed_; + bool record_uma_; DISALLOW_COPY_AND_ASSIGN(FileStream); }; diff --git a/net/base/file_stream_metrics.cc b/net/base/file_stream_metrics.cc new file mode 100644 index 0000000..7ffa96d --- /dev/null +++ b/net/base/file_stream_metrics.cc @@ -0,0 +1,81 @@ +// 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_metrics.h" + +#include "base/logging.h" +#include "base/metrics/histogram.h" + +namespace net { + +namespace { + +void RecordFileErrorTypeCount(FileErrorSource source) { + UMA_HISTOGRAM_ENUMERATION( + "Net.FileErrorType_Counts", source, FILE_ERROR_SOURCE_COUNT); +} + +} // namespace + +void RecordFileError(int error, FileErrorSource source, bool record) { + LOG(ERROR) << " " << __FUNCTION__ << "()" + << " error = " << error + << " source = " << source + << " record = " << record; + + if (!record) + return; + + RecordFileErrorTypeCount(source); + + int bucket = GetFileErrorUmaBucket(error); + + // Fixed values per platform. + static const int max_bucket = MaxFileErrorUmaBucket(); + static const int max_error = MaxFileErrorUmaValue(); + + switch(source) { + case FILE_ERROR_SOURCE_OPEN: + UMA_HISTOGRAM_ENUMERATION("Net.FileError_Open", error, max_error); + UMA_HISTOGRAM_ENUMERATION("Net.FileErrorRange_Open", bucket, max_bucket); + break; + + case FILE_ERROR_SOURCE_WRITE: + UMA_HISTOGRAM_ENUMERATION("Net.FileError_Write", error, max_error); + UMA_HISTOGRAM_ENUMERATION("Net.FileErrorRange_Write", bucket, max_bucket); + break; + + case FILE_ERROR_SOURCE_READ: + UMA_HISTOGRAM_ENUMERATION("Net.FileError_Read", error, max_error); + UMA_HISTOGRAM_ENUMERATION("Net.FileErrorRange_Read", bucket, max_bucket); + break; + + case FILE_ERROR_SOURCE_SEEK: + UMA_HISTOGRAM_ENUMERATION("Net.FileError_Seek", error, max_error); + UMA_HISTOGRAM_ENUMERATION("Net.FileErrorRange_Seek", bucket, max_bucket); + break; + + case FILE_ERROR_SOURCE_FLUSH: + UMA_HISTOGRAM_ENUMERATION("Net.FileError_Flush", error, max_error); + UMA_HISTOGRAM_ENUMERATION("Net.FileErrorRange_Flush", bucket, max_bucket); + break; + + case FILE_ERROR_SOURCE_SET_EOF: + UMA_HISTOGRAM_ENUMERATION("Net.FileError_SetEof", error, max_error); + UMA_HISTOGRAM_ENUMERATION("Net.FileErrorRange_SetEof", bucket, + max_bucket); + break; + + case FILE_ERROR_SOURCE_GET_SIZE: + UMA_HISTOGRAM_ENUMERATION("Net.FileError_GetSize", error, max_error); + UMA_HISTOGRAM_ENUMERATION("Net.FileErrorRange_GetSize", bucket, + max_bucket); + break; + + default: + break; + } +} + +} // namespace net diff --git a/net/base/file_stream_metrics.h b/net/base/file_stream_metrics.h new file mode 100644 index 0000000..cdf16e5 --- /dev/null +++ b/net/base/file_stream_metrics.h @@ -0,0 +1,41 @@ +// 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. + +// File error statistics gathering. + +#ifndef NET_BASE_FILE_STREAM_METRICS_H_ +#define NET_BASE_FILE_STREAM_METRICS_H_ +#pragma once + +namespace net { + +enum FileErrorSource { + FILE_ERROR_SOURCE_OPEN = 0, + FILE_ERROR_SOURCE_WRITE, + FILE_ERROR_SOURCE_READ, + FILE_ERROR_SOURCE_SEEK, + FILE_ERROR_SOURCE_FLUSH, + FILE_ERROR_SOURCE_SET_EOF, + FILE_ERROR_SOURCE_GET_SIZE, + FILE_ERROR_SOURCE_COUNT, +}; + +// UMA error statistics gathering. +// Put the error value into a bucket. +int GetFileErrorUmaBucket(int error); + +// The largest bucket number, plus 1. +int MaxFileErrorUmaBucket(); + +// The highest error value we want to individually report. +int MaxFileErrorUmaValue(); + +// |error| is a platform-specific error (Windows or Posix). +// |source| indicates the operation that resulted in the error. +// |record| is a flag indicating that we are interested in this error. +void RecordFileError(int error, FileErrorSource source, bool record); + +} // namespace net + +#endif // NET_BASE_FILE_STREAM_METRICS_H_ diff --git a/net/base/file_stream_metrics_posix.cc b/net/base/file_stream_metrics_posix.cc new file mode 100644 index 0000000..7407d50 --- /dev/null +++ b/net/base/file_stream_metrics_posix.cc @@ -0,0 +1,21 @@ +// 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_metrics.h" + +namespace net { + +int GetFileErrorUmaBucket(int error) { + return 1; +} + +int MaxFileErrorUmaBucket() { + return 2; +} + +int MaxFileErrorUmaValue() { + return 160; +} + +} // namespace net diff --git a/net/base/file_stream_metrics_win.cc b/net/base/file_stream_metrics_win.cc new file mode 100644 index 0000000..c397e4b --- /dev/null +++ b/net/base/file_stream_metrics_win.cc @@ -0,0 +1,146 @@ +// 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_metrics.h" + +#include <windows.h> + +#include "base/basictypes.h" + +namespace net { + +namespace { + +struct Range { + int low; + int high; +}; + +// The error range list is extracted from WinError.h. +// +// NOTE: The gaps between the ranges need to be recorded too. +// They will have odd-numbered buckets. +const Range kErrorRangeList[] = { + { 0, 321 }, // 2. + { 335, 371 }, // 4. + { 383, 387 }, // 6. + { 399, 404 }, // etc. + { 415, 418 }, + { 431, 433 }, + { 447, 868 }, + { 994, 1471 }, + { 1500, 1513 }, + { 1536, 1553 }, + { 1601, 1654 }, + { 1700, 1834 }, + { 1898, 1938 }, + { 2000, 2024 }, + { 2048, 2085 }, + { 2108, 2110 }, + { 2202, 2203 }, + { 2250, 2251 }, + { 2401, 2405 }, + { 3000, 3021 }, + { 3950, 3951 }, + { 4000, 4007 }, + { 4050, 4066 }, + { 4096, 4116 }, + { 4200, 4215 }, + { 4300, 4353 }, + { 4390, 4395 }, + { 4500, 4501 }, + { 4864, 4905 }, + { 5001, 5090 }, + { 5890, 5953 }, + { 6000, 6023 }, + { 6118, 6119 }, + { 6200, 6201 }, + { 6600, 6649 }, + { 6700, 6732 }, + { 6800, 6856 }, + { 7001, 7071 }, + { 8001, 8018 }, + { 8192, 8263 }, + { 8301, 8640 }, + { 8704, 8705 }, + { 8960, 9053 }, + { 9216, 9218 }, + { 9263, 9276 }, + { 9472, 9506 }, + { 9550, 9573 }, + { 9600, 9622 }, + { 9650, 9656 }, + { 9688, 9723 }, + { 9750, 9754 }, + { 9800, 9802 }, + { 9850, 9853 }, + { 9900, 9907 }, + { 10000, 10072 }, + { 10091, 10113 }, + { 11001, 11034 }, + { 12288, 12335 }, + { 12544, 12559 }, + { 12595, 12597 }, + { 12801, 12803 }, + { 13000, 13026 }, + { 13800, 13933 }, + { 14000, 14111 }, + { 15000, 15039 }, + { 15080, 15086 }, + { 15100, 15109 }, + { 15200, 15208 }, + { 15250, 15251 }, + { 15299, 15302 }, + { 16385, 16436 }, + { 18432, 18454 }, + { 20480, 20486 }, + { 24577, 24607 }, + { 28673, 28698 }, + { 32790, 32816 }, + { 33281, 33322 }, + { 35005, 35024 }, + { 36000, 36004 }, + { 40010, 40011 }, + { 40067, 40069 }, + { 53248, 53293 }, + { 53376, 53382 }, + { 57344, 57360 }, + { 57377, 57394 }, + { 65535, 65536 } // 2 * kNumErrorRanges. +}; +const size_t kNumErrorRanges = ARRAYSIZE_UNSAFE(kErrorRangeList); + +} // namespace + +// 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 to specific buckets. +// If we get hits on the buckets, we can add those values to the values we +// record individually. +// If we get values *between* the buckets, we record those as buckets too. +int GetFileErrorUmaBucket(int error) { + error = HRESULT_CODE(error); + + // This is a linear search, but of a short fixed-size array. + // It also gets called infrequently, on errors. + for (size_t n = 0; n < kNumErrorRanges; ++n) { + if (error < kErrorRangeList[n].low) + return (2 * (n + 1)) - 1; // In gap before the range. + if (error <= kErrorRangeList[n].high) + return 2 * (n + 1); // In the range. + } + + // After the last bucket. + return 2 * kNumErrorRanges + 1; +} + +int MaxFileErrorUmaBucket() { + return 2 * kNumErrorRanges + 2; +} + +int MaxFileErrorUmaValue() { + return kErrorRangeList[0].high + 1; +} + +} // namespace net diff --git a/net/base/file_stream_posix.cc b/net/base/file_stream_posix.cc index 8625016..7a7cbf3 100644 --- a/net/base/file_stream_posix.cc +++ b/net/base/file_stream_posix.cc @@ -25,6 +25,7 @@ #include "base/threading/thread_restrictions.h" #include "base/threading/worker_pool.h" #include "base/synchronization/waitable_event.h" +#include "net/base/file_stream_metrics.h" #include "net/base/net_errors.h" #if defined(OS_ANDROID) @@ -47,52 +48,59 @@ COMPILE_ASSERT(FROM_BEGIN == SEEK_SET && namespace { +int RecordAndMapError(int error, FileErrorSource source, bool record_uma) { + RecordFileError(error, source, record_uma); + return MapSystemError(error); +} + // ReadFile() is a simple wrapper around read() that handles EINTR signals and // calls MapSystemError() to map errno to net error codes. -int ReadFile(base::PlatformFile file, char* buf, int buf_len) { +int ReadFile(base::PlatformFile file, char* buf, int buf_len, bool record_uma) { base::ThreadRestrictions::AssertIOAllowed(); // read(..., 0) returns 0 to indicate end-of-file. // Loop in the case of getting interrupted by a signal. ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len))); if (res == static_cast<ssize_t>(-1)) - return MapSystemError(errno); + RecordAndMapError(errno, FILE_ERROR_SOURCE_READ, record_uma); return static_cast<int>(res); } void ReadFileTask(base::PlatformFile file, char* buf, int buf_len, + bool record_uma, CompletionCallback* callback) { - callback->Run(ReadFile(file, buf, buf_len)); + callback->Run(ReadFile(file, buf, buf_len, record_uma)); } // WriteFile() is a simple wrapper around write() that handles EINTR signals and // calls MapSystemError() to map errno to net error codes. It tries to write to // completion. -int WriteFile(base::PlatformFile file, const char* buf, int buf_len) { +int WriteFile(base::PlatformFile file, const char* buf, int buf_len, + bool record_uma) { base::ThreadRestrictions::AssertIOAllowed(); ssize_t res = HANDLE_EINTR(write(file, buf, buf_len)); if (res == -1) - return MapSystemError(errno); + RecordAndMapError(errno, FILE_ERROR_SOURCE_WRITE, record_uma); return res; } void WriteFileTask(base::PlatformFile file, const char* buf, - int buf_len, + int buf_len, bool record_uma, CompletionCallback* callback) { - callback->Run(WriteFile(file, buf, buf_len)); + callback->Run(WriteFile(file, buf, buf_len, record_uma)); } // FlushFile() is a simple wrapper around fsync() that handles EINTR signals and // calls MapSystemError() to map errno to net error codes. It tries to flush to // completion. -int FlushFile(base::PlatformFile file) { +int FlushFile(base::PlatformFile file, bool record_uma) { base::ThreadRestrictions::AssertIOAllowed(); ssize_t res = HANDLE_EINTR(fsync(file)); if (res == -1) - return MapSystemError(errno); + RecordAndMapError(errno, FILE_ERROR_SOURCE_FLUSH, record_uma); return res; } @@ -144,6 +152,10 @@ class FileStream::AsyncContext { // |result| is the result of the Read/Write task. void OnBackgroundIOCompleted(int result); + void EnableErrorStatistics() { + record_uma_ = true; + } + private: // Always called on the IO thread, either directly by a task on the // MessageLoop or by ~AsyncContext(). @@ -167,6 +179,7 @@ class FileStream::AsyncContext { CancelableCallbackTask* message_loop_task_; bool is_closing_; + bool record_uma_; DISALLOW_COPY_AND_ASSIGN(AsyncContext); }; @@ -178,7 +191,8 @@ FileStream::AsyncContext::AsyncContext() this, &AsyncContext::OnBackgroundIOCompleted), background_io_completed_(true, false), message_loop_task_(NULL), - is_closing_(false) {} + is_closing_(false), + record_uma_(false) {} FileStream::AsyncContext::~AsyncContext() { is_closing_ = true; @@ -207,6 +221,7 @@ void FileStream::AsyncContext::InitiateAsyncRead( NewRunnableFunction( &ReadFileTask, file, buf, buf_len, + record_uma_, &background_io_completed_callback_), true /* task_is_slow */); } @@ -221,6 +236,7 @@ void FileStream::AsyncContext::InitiateAsyncWrite( NewRunnableFunction( &WriteFileTask, file, buf, buf_len, + record_uma_, &background_io_completed_callback_), true /* task_is_slow */); } @@ -261,14 +277,16 @@ void FileStream::AsyncContext::RunAsynchronousCallback() { FileStream::FileStream() : file_(base::kInvalidPlatformFileValue), open_flags_(0), - auto_closed_(true) { + auto_closed_(true), + record_uma_(false) { DCHECK(!IsOpen()); } FileStream::FileStream(base::PlatformFile file, int flags) : file_(file), open_flags_(flags), - auto_closed_(false) { + auto_closed_(false), + record_uma_(false) { // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to // make sure we will perform asynchronous File IO to it. if (flags & base::PLATFORM_FILE_ASYNC) { @@ -301,13 +319,11 @@ int FileStream::Open(const FilePath& path, int open_flags) { open_flags_ = open_flags; file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL); - if (file_ == base::kInvalidPlatformFileValue) { - return MapSystemError(errno); - } + if (file_ == base::kInvalidPlatformFileValue) + return RecordAndMapError(errno, FILE_ERROR_SOURCE_OPEN, record_uma_); - if (open_flags_ & base::PLATFORM_FILE_ASYNC) { + if (open_flags_ & base::PLATFORM_FILE_ASYNC) async_context_.reset(new AsyncContext()); - } return OK; } @@ -328,7 +344,7 @@ int64 FileStream::Seek(Whence whence, int64 offset) { off_t res = lseek(file_, static_cast<off_t>(offset), static_cast<int>(whence)); if (res == static_cast<off_t>(-1)) - return MapSystemError(errno); + return RecordAndMapError(errno, FILE_ERROR_SOURCE_SEEK, record_uma_); return res; } @@ -345,7 +361,7 @@ int64 FileStream::Available() { struct stat info; if (fstat(file_, &info) != 0) - return MapSystemError(errno); + return RecordAndMapError(errno, FILE_ERROR_SOURCE_GET_SIZE, record_uma_); int64 size = static_cast<int64>(info.st_size); DCHECK_GT(size, cur_pos); @@ -366,10 +382,12 @@ int FileStream::Read( DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); // If we're in async, make sure we don't have a request in flight. DCHECK(!async_context_->callback()); + if (record_uma_) + async_context_->EnableErrorStatistics(); async_context_->InitiateAsyncRead(file_, buf, buf_len, callback); return ERR_IO_PENDING; } else { - return ReadFile(file_, buf, buf_len); + return ReadFile(file_, buf, buf_len, record_uma_); } } @@ -406,10 +424,12 @@ int FileStream::Write( DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); // If we're in async, make sure we don't have a request in flight. DCHECK(!async_context_->callback()); + if (record_uma_) + async_context_->EnableErrorStatistics(); async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback); return ERR_IO_PENDING; } else { - return WriteFile(file_, buf, buf_len); + return WriteFile(file_, buf, buf_len, record_uma_); } } @@ -429,15 +449,21 @@ int64 FileStream::Truncate(int64 bytes) { // And truncate the file. int result = ftruncate(file_, bytes); - return result == 0 ? seek_position : - static_cast<int64>(MapSystemError(errno)); + if (result == 0) + return seek_position; + + return RecordAndMapError(errno, FILE_ERROR_SOURCE_SET_EOF, record_uma_); } int FileStream::Flush() { if (!IsOpen()) return ERR_UNEXPECTED; - return FlushFile(file_); + return FlushFile(file_, record_uma_); +} + +void FileStream::EnableErrorStatistics() { + record_uma_ = true; } } // namespace net diff --git a/net/base/file_stream_win.cc b/net/base/file_stream_win.cc index 314687e..4e3e66c 100644 --- a/net/base/file_stream_win.cc +++ b/net/base/file_stream_win.cc @@ -11,6 +11,7 @@ #include "base/message_loop.h" #include "base/metrics/histogram.h" #include "base/threading/thread_restrictions.h" +#include "net/base/file_stream_metrics.h" #include "net/base/net_errors.h" namespace net { @@ -33,12 +34,22 @@ static void IncrementOffset(OVERLAPPED* overlapped, DWORD count) { SetOffset(overlapped, offset); } +namespace { + +int RecordAndMapError(int error, FileErrorSource source, bool record_uma) { + RecordFileError(error, source, record_uma); + return MapSystemError(error); +} + +} // namespace + // FileStream::AsyncContext ---------------------------------------------- class FileStream::AsyncContext : public MessageLoopForIO::IOHandler { public: AsyncContext(FileStream* owner) - : owner_(owner), context_(), callback_(NULL), is_closing_(false) { + : owner_(owner), context_(), callback_(NULL), is_closing_(false), + record_uma_(false), error_source_(FILE_ERROR_SOURCE_COUNT) { context_.handler = this; } ~AsyncContext(); @@ -48,6 +59,12 @@ class FileStream::AsyncContext : public MessageLoopForIO::IOHandler { OVERLAPPED* overlapped() { return &context_.overlapped; } CompletionCallback* callback() const { return callback_; } + void set_error_source(FileErrorSource source) { error_source_ = source; } + + void EnableErrorStatistics() { + record_uma_ = true; + } + private: virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, DWORD bytes_read, DWORD error); @@ -56,6 +73,8 @@ class FileStream::AsyncContext : public MessageLoopForIO::IOHandler { MessageLoopForIO::IOContext context_; CompletionCallback* callback_; bool is_closing_; + bool record_uma_; + FileErrorSource error_source_; }; FileStream::AsyncContext::~AsyncContext() { @@ -91,7 +110,7 @@ void FileStream::AsyncContext::OnIOCompleted( int result = static_cast<int>(bytes_read); if (error && error != ERROR_HANDLE_EOF) - result = MapSystemError(error); + result = RecordAndMapError(error, error_source_, record_uma_); if (bytes_read) IncrementOffset(&context->overlapped, bytes_read); @@ -106,13 +125,15 @@ void FileStream::AsyncContext::OnIOCompleted( FileStream::FileStream() : file_(INVALID_HANDLE_VALUE), open_flags_(0), - auto_closed_(true) { + auto_closed_(true), + record_uma_(false) { } FileStream::FileStream(base::PlatformFile file, int flags) : file_(file), open_flags_(flags), - auto_closed_(false) { + auto_closed_(false), + record_uma_(false) { // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to // make sure we will perform asynchronous File IO to it. if (flags & base::PLATFORM_FILE_ASYNC) { @@ -149,11 +170,13 @@ int FileStream::Open(const FilePath& path, int open_flags) { if (file_ == INVALID_HANDLE_VALUE) { DWORD error = GetLastError(); LOG(WARNING) << "Failed to open file: " << error; - return MapSystemError(error); + return RecordAndMapError(error, FILE_ERROR_SOURCE_OPEN, record_uma_); } if (open_flags_ & base::PLATFORM_FILE_ASYNC) { async_context_.reset(new AsyncContext(this)); + if (record_uma_) + async_context_->EnableErrorStatistics(); MessageLoopForIO::current()->RegisterIOHandler(file_, async_context_.get()); } @@ -168,6 +191,7 @@ bool FileStream::IsOpen() const { int64 FileStream::Seek(Whence whence, int64 offset) { if (!IsOpen()) return ERR_UNEXPECTED; + DCHECK(!async_context_.get() || !async_context_->callback()); LARGE_INTEGER distance, result; @@ -176,10 +200,12 @@ int64 FileStream::Seek(Whence whence, int64 offset) { if (!SetFilePointerEx(file_, distance, &result, move_method)) { DWORD error = GetLastError(); LOG(WARNING) << "SetFilePointerEx failed: " << error; - return MapSystemError(error); + return RecordAndMapError(error, FILE_ERROR_SOURCE_SEEK, record_uma_); } - if (async_context_.get()) + if (async_context_.get()) { + async_context_->set_error_source(FILE_ERROR_SOURCE_SEEK); SetOffset(async_context_->overlapped(), result); + } return result.QuadPart; } @@ -197,7 +223,7 @@ int64 FileStream::Available() { if (!GetFileSizeEx(file_, &file_size)) { DWORD error = GetLastError(); LOG(WARNING) << "GetFileSizeEx failed: " << error; - return MapSystemError(error); + return RecordAndMapError(error, FILE_ERROR_SOURCE_GET_SIZE, record_uma_); } return file_size.QuadPart - cur_pos; @@ -207,6 +233,7 @@ int FileStream::Read( char* buf, int buf_len, CompletionCallback* callback) { if (!IsOpen()) return ERR_UNEXPECTED; + DCHECK(open_flags_ & base::PLATFORM_FILE_READ); OVERLAPPED* overlapped = NULL; @@ -214,6 +241,7 @@ int FileStream::Read( DCHECK(callback); DCHECK(!async_context_->callback()); overlapped = async_context_->overlapped(); + async_context_->set_error_source(FILE_ERROR_SOURCE_READ); } else { DCHECK(!callback); base::ThreadRestrictions::AssertIOAllowed(); @@ -231,7 +259,7 @@ int FileStream::Read( rv = 0; // Report EOF by returning 0 bytes read. } else { LOG(WARNING) << "ReadFile failed: " << error; - rv = MapSystemError(error); + rv = RecordAndMapError(error, FILE_ERROR_SOURCE_READ, record_uma_); } } else if (overlapped) { async_context_->IOCompletionIsPending(callback); @@ -267,6 +295,7 @@ int FileStream::Write( const char* buf, int buf_len, CompletionCallback* callback) { if (!IsOpen()) return ERR_UNEXPECTED; + DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); OVERLAPPED* overlapped = NULL; @@ -274,6 +303,7 @@ int FileStream::Write( DCHECK(callback); DCHECK(!async_context_->callback()); overlapped = async_context_->overlapped(); + async_context_->set_error_source(FILE_ERROR_SOURCE_WRITE); } else { DCHECK(!callback); base::ThreadRestrictions::AssertIOAllowed(); @@ -288,7 +318,7 @@ int FileStream::Write( rv = ERR_IO_PENDING; } else { LOG(WARNING) << "WriteFile failed: " << error; - rv = MapSystemError(error); + rv = RecordAndMapError(error, FILE_ERROR_SOURCE_WRITE, record_uma_); } } else if (overlapped) { async_context_->IOCompletionIsPending(callback); @@ -310,10 +340,9 @@ int FileStream::Flush() { return OK; } - int rv; - DWORD error = GetLastError(); - rv = MapSystemError(error); - return rv; + return RecordAndMapError(GetLastError(), + FILE_ERROR_SOURCE_FLUSH, + record_uma_); } int64 FileStream::Truncate(int64 bytes) { @@ -335,11 +364,18 @@ int64 FileStream::Truncate(int64 bytes) { if (!result) { DWORD error = GetLastError(); LOG(WARNING) << "SetEndOfFile failed: " << error; - return MapSystemError(error); + return RecordAndMapError(error, FILE_ERROR_SOURCE_SET_EOF, record_uma_); } // Success. return seek_position; } +void FileStream::EnableErrorStatistics() { + record_uma_ = true; + + if (async_context_.get()) + async_context_->EnableErrorStatistics(); +} + } // namespace net diff --git a/net/base/net_errors_posix.cc b/net/base/net_errors_posix.cc index 143912c..0d8b7de 100644 --- a/net/base/net_errors_posix.cc +++ b/net/base/net_errors_posix.cc @@ -5,12 +5,19 @@ #include "net/base/net_errors.h" #include <errno.h> +#include <stdlib.h> +#include <string> +#include <unistd.h> #include "base/logging.h" +#include "base/stringprintf.h" namespace net { Error MapSystemError(int os_error) { + if (os_error != 0) + DVLOG(2) << "Error " << os_error; + // There are numerous posix error codes, but these are the ones we thus far // find interesting. switch (os_error) { @@ -98,6 +105,8 @@ Error MapSystemError(int os_error) { return ERR_ACCESS_DENIED; case EUSERS: // Too many users. return ERR_INSUFFICIENT_RESOURCES; + case EMFILE: // Too many open files. + return ERR_INSUFFICIENT_RESOURCES; case 0: return OK; diff --git a/net/base/net_errors_win.cc b/net/base/net_errors_win.cc index fcede60..74ed228 100644 --- a/net/base/net_errors_win.cc +++ b/net/base/net_errors_win.cc @@ -12,6 +12,9 @@ namespace net { // Map winsock and system errors to Chromium errors. Error MapSystemError(int os_error) { + if (os_error != 0) + DVLOG(2) << "Error " << os_error; + // There are numerous Winsock error codes, but these are the ones we thus far // find interesting. switch (os_error) { diff --git a/net/net.gyp b/net/net.gyp index b4ce67a..0bc2862 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -102,6 +102,10 @@ 'base/ev_root_ca_metadata.cc', 'base/ev_root_ca_metadata.h', 'base/file_stream.h', + 'base/file_stream_metrics.h', + 'base/file_stream_metrics.cc', + 'base/file_stream_metrics_posix.cc', + 'base/file_stream_metrics_win.cc', 'base/file_stream_posix.cc', 'base/file_stream_win.cc', 'base/filter.cc', |