| // Copyright 2018 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 "base/metrics/persistent_histogram_storage.h" |
| |
| #include "base/files/file_util.h" |
| #include "base/files/important_file_writer.h" |
| #include "base/logging.h" |
| #include "base/metrics/persistent_histogram_allocator.h" |
| #include "base/metrics/persistent_memory_allocator.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| |
| #if defined(STARBOARD) |
| #include "starboard/common/file.h" |
| #endif |
| |
| namespace { |
| |
| constexpr size_t kAllocSize = 1 << 20; // 1 MiB |
| |
| } // namespace |
| |
| namespace base { |
| |
| PersistentHistogramStorage::PersistentHistogramStorage( |
| StringPiece allocator_name, |
| StorageDirManagement storage_dir_management) |
| : storage_dir_management_(storage_dir_management) { |
| DCHECK(!allocator_name.empty()); |
| DCHECK(IsStringASCII(allocator_name)); |
| |
| GlobalHistogramAllocator::CreateWithLocalMemory(kAllocSize, |
| 0, // No identifier. |
| allocator_name); |
| GlobalHistogramAllocator::Get()->CreateTrackingHistograms(allocator_name); |
| } |
| |
| PersistentHistogramStorage::~PersistentHistogramStorage() { |
| PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get(); |
| allocator->UpdateTrackingHistograms(); |
| |
| // TODO(chengx): Investigate making early return depend on whethere there are |
| // metrics to report at this point or not. |
| if (disabled_) |
| return; |
| |
| // Stop if the storage base directory has not been properly set. |
| if (storage_base_dir_.empty()) { |
| LOG(ERROR) |
| << "Could not write \"" << allocator->Name() |
| << "\" persistent histograms to file as the storage base directory " |
| "is not properly set."; |
| return; |
| } |
| |
| FilePath storage_dir = storage_base_dir_.AppendASCII(allocator->Name()); |
| |
| switch (storage_dir_management_) { |
| case StorageDirManagement::kCreate: |
| if (!CreateDirectory(storage_dir)) { |
| LOG(ERROR) |
| << "Could not write \"" << allocator->Name() |
| << "\" persistent histograms to file as the storage directory " |
| "cannot be created."; |
| return; |
| } |
| break; |
| case StorageDirManagement::kUseExisting: |
| if (!DirectoryExists(storage_dir)) { |
| // When the consumer of this class decides to use an existing storage |
| // directory, it should ensure the directory's existence if it's |
| // essential. |
| LOG(ERROR) |
| << "Could not write \"" << allocator->Name() |
| << "\" persistent histograms to file as the storage directory " |
| "does not exist."; |
| return; |
| } |
| break; |
| } |
| |
| // Save data using the current time as the filename. The actual filename |
| // doesn't matter (so long as it ends with the correct extension) but this |
| // works as well as anything. |
| Time::Exploded exploded; |
| Time::Now().LocalExplode(&exploded); |
| const FilePath file_path = |
| storage_dir |
| .AppendASCII(StringPrintf("%04d%02d%02d%02d%02d%02d", exploded.year, |
| exploded.month, exploded.day_of_month, |
| exploded.hour, exploded.minute, |
| exploded.second)) |
| .AddExtension(PersistentMemoryAllocator::kFileExtension); |
| |
| StringPiece contents(static_cast<const char*>(allocator->data()), |
| allocator->used()); |
| #if defined(STARBOARD) |
| // All path should be UTF8 above Starboard. |
| SbFileError error; |
| bool out_created; |
| starboard::ScopedFile sb_file(file_path.AsUTF8Unsafe().c_str(), |
| kSbFileCreateAlways | kSbFileWrite, |
| &out_created, &error); |
| |
| int bytes_written = sb_file.WriteAll(contents.data(), contents.size()); |
| if (bytes_written == contents.size()) { |
| #else |
| if (!ImportantFileWriter::WriteFileAtomically(file_path, contents)) { |
| #endif |
| LOG(ERROR) << "Persistent histograms fail to write to file: " |
| << file_path.value(); |
| } |
| } |
| |
| } // namespace base |