| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/metrics/persistent_histogram_allocator.h" | 5 #include "base/metrics/persistent_histogram_allocator.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 | 31 |
| 32 // Type identifiers used when storing in persistent memory so they can be | 32 // Type identifiers used when storing in persistent memory so they can be |
| 33 // identified during extraction; the first 4 bytes of the SHA1 of the name | 33 // identified during extraction; the first 4 bytes of the SHA1 of the name |
| 34 // is used as a unique integer. A "version number" is added to the base | 34 // is used as a unique integer. A "version number" is added to the base |
| 35 // so that, if the structure of that object changes, stored older versions | 35 // so that, if the structure of that object changes, stored older versions |
| 36 // will be safely ignored. | 36 // will be safely ignored. |
| 37 enum : uint32_t { | 37 enum : uint32_t { |
| 38 kTypeIdHistogram = 0xF1645910 + 2, // SHA1(Histogram) v2 | 38 kTypeIdHistogram = 0xF1645910 + 2, // SHA1(Histogram) v2 |
| 39 kTypeIdRangesArray = 0xBCEA225A + 1, // SHA1(RangesArray) v1 | 39 kTypeIdRangesArray = 0xBCEA225A + 1, // SHA1(RangesArray) v1 |
| 40 kTypeIdCountsArray = 0x53215530 + 1, // SHA1(CountsArray) v1 | 40 kTypeIdCountsArray = 0x53215530 + 1, // SHA1(CountsArray) v1 |
| 41 |
| 42 kTypeIdHistogramUnderConstruction = ~kTypeIdHistogram, |
| 41 }; | 43 }; |
| 42 | 44 |
| 43 // The current globally-active persistent allocator for all new histograms. | 45 // The current globally-active persistent allocator for all new histograms. |
| 44 // The object held here will obviously not be destructed at process exit | 46 // The object held here will obviously not be destructed at process exit |
| 45 // but that's best since PersistentMemoryAllocator objects (that underlie | 47 // but that's best since PersistentMemoryAllocator objects (that underlie |
| 46 // GlobalHistogramAllocator objects) are explicitly forbidden from doing | 48 // GlobalHistogramAllocator objects) are explicitly forbidden from doing |
| 47 // anything essential at exit anyway due to the fact that they depend on data | 49 // anything essential at exit anyway due to the fact that they depend on data |
| 48 // managed elsewhere and which could be destructed first. | 50 // managed elsewhere and which could be destructed first. |
| 49 GlobalHistogramAllocator* g_allocator = nullptr; | 51 GlobalHistogramAllocator* g_allocator = nullptr; |
| 50 | 52 |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 Reference ref) { | 269 Reference ref) { |
| 268 // Unfortunately, the histogram "pickle" methods cannot be used as part of | 270 // Unfortunately, the histogram "pickle" methods cannot be used as part of |
| 269 // the persistance because the deserialization methods always create local | 271 // the persistance because the deserialization methods always create local |
| 270 // count data (while these must reference the persistent counts) and always | 272 // count data (while these must reference the persistent counts) and always |
| 271 // add it to the local list of known histograms (while these may be simple | 273 // add it to the local list of known histograms (while these may be simple |
| 272 // references to histograms in other processes). | 274 // references to histograms in other processes). |
| 273 PersistentHistogramData* histogram_data = | 275 PersistentHistogramData* histogram_data = |
| 274 memory_allocator_->GetAsObject<PersistentHistogramData>( | 276 memory_allocator_->GetAsObject<PersistentHistogramData>( |
| 275 ref, kTypeIdHistogram); | 277 ref, kTypeIdHistogram); |
| 276 size_t length = memory_allocator_->GetAllocSize(ref); | 278 size_t length = memory_allocator_->GetAllocSize(ref); |
| 279 |
| 280 // Check that metadata is reasonable: name is NUL terminated and non-empty, |
| 281 // ID fields have been loaded with a hash of the name (0 is considered |
| 282 // unset/invalid). |
| 277 if (!histogram_data || | 283 if (!histogram_data || |
| 278 reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') { | 284 reinterpret_cast<char*>(histogram_data)[length - 1] != '\0' || |
| 285 histogram_data->name[0] == '\0' || |
| 286 histogram_data->samples_metadata.id == 0 || |
| 287 histogram_data->logged_metadata.id == 0) { |
| 279 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA); | 288 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA); |
| 280 NOTREACHED(); | 289 NOTREACHED(); |
| 281 return nullptr; | 290 return nullptr; |
| 282 } | 291 } |
| 283 return CreateHistogram(histogram_data); | 292 return CreateHistogram(histogram_data); |
| 284 } | 293 } |
| 285 | 294 |
| 286 std::unique_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram( | 295 std::unique_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram( |
| 287 HistogramType histogram_type, | 296 HistogramType histogram_type, |
| 288 const std::string& name, | 297 const std::string& name, |
| 289 int minimum, | 298 int minimum, |
| 290 int maximum, | 299 int maximum, |
| 291 const BucketRanges* bucket_ranges, | 300 const BucketRanges* bucket_ranges, |
| 292 int32_t flags, | 301 int32_t flags, |
| 293 Reference* ref_ptr) { | 302 Reference* ref_ptr) { |
| 294 // If the allocator is corrupt, don't waste time trying anything else. | 303 // If the allocator is corrupt, don't waste time trying anything else. |
| 295 // This also allows differentiating on the dashboard between allocations | 304 // This also allows differentiating on the dashboard between allocations |
| 296 // failed due to a corrupt allocator and the number of process instances | 305 // failed due to a corrupt allocator and the number of process instances |
| 297 // with one, the latter being idicated by "newly corrupt", below. | 306 // with one, the latter being idicated by "newly corrupt", below. |
| 298 if (memory_allocator_->IsCorrupt()) { | 307 if (memory_allocator_->IsCorrupt()) { |
| 299 RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_CORRUPT); | 308 RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_CORRUPT); |
| 300 return nullptr; | 309 return nullptr; |
| 301 } | 310 } |
| 302 | 311 |
| 303 // Create the metadata necessary for a persistent sparse histogram. This | 312 // Create the metadata necessary for a persistent sparse histogram. This |
| 304 // is done first because it is a small subset of what is required for | 313 // is done first because it is a small subset of what is required for |
| 305 // other histograms. | 314 // other histograms. The type is "under construction" so that a crash |
| 315 // during the datafill doesn't leave a bad record around that could cause |
| 316 // confusion by another process trying to read it. It will be corrected |
| 317 // once histogram construction is complete. |
| 306 PersistentMemoryAllocator::Reference histogram_ref = | 318 PersistentMemoryAllocator::Reference histogram_ref = |
| 307 memory_allocator_->Allocate( | 319 memory_allocator_->Allocate( |
| 308 offsetof(PersistentHistogramData, name) + name.length() + 1, | 320 offsetof(PersistentHistogramData, name) + name.length() + 1, |
| 309 kTypeIdHistogram); | 321 kTypeIdHistogramUnderConstruction); |
| 310 PersistentHistogramData* histogram_data = | 322 PersistentHistogramData* histogram_data = |
| 311 memory_allocator_->GetAsObject<PersistentHistogramData>(histogram_ref, | 323 memory_allocator_->GetAsObject<PersistentHistogramData>( |
| 312 kTypeIdHistogram); | 324 histogram_ref, kTypeIdHistogramUnderConstruction); |
| 313 if (histogram_data) { | 325 if (histogram_data) { |
| 314 memcpy(histogram_data->name, name.c_str(), name.size() + 1); | 326 memcpy(histogram_data->name, name.c_str(), name.size() + 1); |
| 315 histogram_data->histogram_type = histogram_type; | 327 histogram_data->histogram_type = histogram_type; |
| 316 histogram_data->flags = flags | HistogramBase::kIsPersistent; | 328 histogram_data->flags = flags | HistogramBase::kIsPersistent; |
| 317 } | 329 } |
| 318 | 330 |
| 319 // Create the remaining metadata necessary for regular histograms. | 331 // Create the remaining metadata necessary for regular histograms. |
| 320 if (histogram_type != SPARSE_HISTOGRAM) { | 332 if (histogram_type != SPARSE_HISTOGRAM) { |
| 321 size_t bucket_count = bucket_ranges->bucket_count(); | 333 size_t bucket_count = bucket_ranges->bucket_count(); |
| 322 size_t counts_bytes = CalculateRequiredCountsBytes(bucket_count); | 334 size_t counts_bytes = CalculateRequiredCountsBytes(bucket_count); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 358 } | 370 } |
| 359 | 371 |
| 360 if (histogram_data) { | 372 if (histogram_data) { |
| 361 // Create the histogram using resources in persistent memory. This ends up | 373 // Create the histogram using resources in persistent memory. This ends up |
| 362 // resolving the "ref" values stored in histogram_data instad of just | 374 // resolving the "ref" values stored in histogram_data instad of just |
| 363 // using what is already known above but avoids duplicating the switch | 375 // using what is already known above but avoids duplicating the switch |
| 364 // statement here and serves as a double-check that everything is | 376 // statement here and serves as a double-check that everything is |
| 365 // correct before commiting the new histogram to persistent space. | 377 // correct before commiting the new histogram to persistent space. |
| 366 std::unique_ptr<HistogramBase> histogram = CreateHistogram(histogram_data); | 378 std::unique_ptr<HistogramBase> histogram = CreateHistogram(histogram_data); |
| 367 DCHECK(histogram); | 379 DCHECK(histogram); |
| 380 DCHECK_NE(0U, histogram_data->samples_metadata.id); |
| 381 DCHECK_NE(0U, histogram_data->logged_metadata.id); |
| 382 memory_allocator_->ChangeType(histogram_ref, kTypeIdHistogram, |
| 383 kTypeIdHistogramUnderConstruction); |
| 384 |
| 368 if (ref_ptr != nullptr) | 385 if (ref_ptr != nullptr) |
| 369 *ref_ptr = histogram_ref; | 386 *ref_ptr = histogram_ref; |
| 370 | 387 |
| 371 // By storing the reference within the allocator to this histogram, the | 388 // By storing the reference within the allocator to this histogram, the |
| 372 // next import (which will happen before the next histogram creation) | 389 // next import (which will happen before the next histogram creation) |
| 373 // will know to skip it. | 390 // will know to skip it. |
| 374 // See also the comment in ImportHistogramsToStatisticsRecorder(). | 391 // See also the comment in ImportHistogramsToStatisticsRecorder(). |
| 375 subtle::NoBarrier_Store(&last_created_, histogram_ref); | 392 subtle::NoBarrier_Store(&last_created_, histogram_ref); |
| 376 return histogram; | 393 return histogram; |
| 377 } | 394 } |
| (...skipping 536 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 914 while (true) { | 931 while (true) { |
| 915 std::unique_ptr<HistogramBase> histogram = | 932 std::unique_ptr<HistogramBase> histogram = |
| 916 import_iterator_.GetNextWithIgnore(record_to_ignore); | 933 import_iterator_.GetNextWithIgnore(record_to_ignore); |
| 917 if (!histogram) | 934 if (!histogram) |
| 918 break; | 935 break; |
| 919 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); | 936 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); |
| 920 } | 937 } |
| 921 } | 938 } |
| 922 | 939 |
| 923 } // namespace base | 940 } // namespace base |
| OLD | NEW |