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 |