diff options
Diffstat (limited to 'chrome/browser/fragmentation_checker_win.cc')
-rw-r--r-- | chrome/browser/fragmentation_checker_win.cc | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/chrome/browser/fragmentation_checker_win.cc b/chrome/browser/fragmentation_checker_win.cc new file mode 100644 index 0000000..04d4ac6 --- /dev/null +++ b/chrome/browser/fragmentation_checker_win.cc @@ -0,0 +1,114 @@ +// 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 "chrome/browser/fragmentation_checker_win.h" + +#include <windows.h> +#include <winioctl.h> + +#include <vector> + +#include "base/file_path.h" +#include "base/logging.h" +#include "base/metrics/histogram.h" +#include "base/platform_file.h" +#include "base/path_service.h" + +namespace { + +size_t ComputeRetrievalPointersBufferSize(int number_of_extents) { + // We make a redundant access to buffer.ExtentCount (which is always 0) below + // to avoid C4101 on MSVC2010. + RETRIEVAL_POINTERS_BUFFER buffer = {0}; + return sizeof(buffer) + (number_of_extents - 1) * sizeof(buffer.Extents) + + buffer.ExtentCount; +} + +} // namespace + +namespace fragmentation_checker { + +int CountFileExtents(const FilePath& file_path) { + int file_extents_count = 0; + + base::PlatformFileError error_code = base::PLATFORM_FILE_ERROR_FAILED; + base::PlatformFile file_handle = CreatePlatformFile( + file_path, + base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, + NULL, + &error_code); + if (error_code == base::PLATFORM_FILE_OK) { + STARTING_VCN_INPUT_BUFFER starting_vcn_input_buffer = {0}; + + // Compute an output size capable of holding 16 extents at first. This will + // fail when the number of extents exceeds 16, in which case we make + // a bigger buffer capable of holding up to kMaxExtentCounts. + int extents_guess = 16; + size_t output_size = ComputeRetrievalPointersBufferSize(extents_guess); + std::vector<uint8> retrieval_pointers_buffer(output_size); + + DWORD bytes_returned = 0; + + bool result = false; + do { + result = DeviceIoControl( + file_handle, + FSCTL_GET_RETRIEVAL_POINTERS, + reinterpret_cast<void*>(&starting_vcn_input_buffer), + sizeof(starting_vcn_input_buffer), + reinterpret_cast<void*>(&retrieval_pointers_buffer[0]), + retrieval_pointers_buffer.size(), + &bytes_returned, + NULL) != FALSE; + + if (!result) { + if (GetLastError() == ERROR_MORE_DATA) { + // Grow the extents we can handle + extents_guess *= 2; + if (extents_guess > kMaxExtentCount) { + LOG(ERROR) << "FSCTL_GET_RETRIEVAL_POINTERS output buffer exceeded " + "maximum size."; + file_extents_count = kMaxExtentCount; + break; + } + output_size = ComputeRetrievalPointersBufferSize(extents_guess); + retrieval_pointers_buffer.assign(output_size, 0); + } else { + PLOG(ERROR) << "FSCTL_GET_RETRIEVAL_POINTERS failed."; + break; + } + } + } while (!result); + + if (result) { + RETRIEVAL_POINTERS_BUFFER* retrieval_pointers = + reinterpret_cast<RETRIEVAL_POINTERS_BUFFER*>( + &retrieval_pointers_buffer[0]); + file_extents_count = static_cast<int>(retrieval_pointers->ExtentCount); + } else { + LOG(ERROR) << "Failed to retrieve extents."; + } + } else { + LOG(ERROR) << "Failed to open module file to check extents. Error code = " + << error_code; + } + + return file_extents_count; +} + +void RecordFragmentationMetricForCurrentModule() { + FilePath module_path; + if (PathService::Get(base::FILE_MODULE, &module_path)) { + int file_extent_count = CountFileExtents(module_path); + UMA_HISTOGRAM_CUSTOM_COUNTS("Fragmentation.ModuleExtents", + file_extent_count, + 0, + kMaxExtentCount, + 50); + } else { + NOTREACHED() << "Could not get path to current module."; + } +} + +} // namespace fragmentation_checker |