| 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> |
| 8 |
| 7 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
| 8 #include "base/logging.h" | 10 #include "base/logging.h" |
| 9 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/ptr_util.h" |
| 10 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 11 #include "base/metrics/histogram_base.h" | 13 #include "base/metrics/histogram_base.h" |
| 12 #include "base/metrics/histogram_samples.h" | 14 #include "base/metrics/histogram_samples.h" |
| 13 #include "base/metrics/sparse_histogram.h" | 15 #include "base/metrics/sparse_histogram.h" |
| 14 #include "base/metrics/statistics_recorder.h" | 16 #include "base/metrics/statistics_recorder.h" |
| 15 #include "base/synchronization/lock.h" | 17 #include "base/synchronization/lock.h" |
| 16 | 18 |
| 17 // TODO(bcwhite): Order these methods to match the header file. The current | 19 // TODO(bcwhite): Order these methods to match the header file. The current |
| 18 // order is only temporary in order to aid review of the transition from | 20 // order is only temporary in order to aid review of the transition from |
| 19 // a non-class implementation. | 21 // a non-class implementation. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 40 // The object held here will obviously not be destructed at process exit | 42 // The object held here will obviously not be destructed at process exit |
| 41 // but that's best since PersistentMemoryAllocator objects (that underlie | 43 // but that's best since PersistentMemoryAllocator objects (that underlie |
| 42 // PersistentHistogramAllocator objects) are explicitly forbidden from doing | 44 // PersistentHistogramAllocator objects) are explicitly forbidden from doing |
| 43 // anything essential at exit anyway due to the fact that they depend on data | 45 // anything essential at exit anyway due to the fact that they depend on data |
| 44 // managed elsewhere and which could be destructed first. | 46 // managed elsewhere and which could be destructed first. |
| 45 PersistentHistogramAllocator* g_allocator; | 47 PersistentHistogramAllocator* g_allocator; |
| 46 | 48 |
| 47 // Take an array of range boundaries and create a proper BucketRanges object | 49 // Take an array of range boundaries and create a proper BucketRanges object |
| 48 // which is returned to the caller. A return of nullptr indicates that the | 50 // which is returned to the caller. A return of nullptr indicates that the |
| 49 // passed boundaries are invalid. | 51 // passed boundaries are invalid. |
| 50 scoped_ptr<BucketRanges> CreateRangesFromData( | 52 std::unique_ptr<BucketRanges> CreateRangesFromData( |
| 51 HistogramBase::Sample* ranges_data, | 53 HistogramBase::Sample* ranges_data, |
| 52 uint32_t ranges_checksum, | 54 uint32_t ranges_checksum, |
| 53 size_t count) { | 55 size_t count) { |
| 54 // To avoid racy destruction at shutdown, the following may be leaked. | 56 // To avoid racy destruction at shutdown, the following may be leaked. |
| 55 scoped_ptr<BucketRanges> ranges(new BucketRanges(count)); | 57 std::unique_ptr<BucketRanges> ranges(new BucketRanges(count)); |
| 56 DCHECK_EQ(count, ranges->size()); | 58 DCHECK_EQ(count, ranges->size()); |
| 57 for (size_t i = 0; i < count; ++i) { | 59 for (size_t i = 0; i < count; ++i) { |
| 58 if (i > 0 && ranges_data[i] <= ranges_data[i - 1]) | 60 if (i > 0 && ranges_data[i] <= ranges_data[i - 1]) |
| 59 return nullptr; | 61 return nullptr; |
| 60 ranges->set_range(i, ranges_data[i]); | 62 ranges->set_range(i, ranges_data[i]); |
| 61 } | 63 } |
| 62 | 64 |
| 63 ranges->ResetChecksum(); | 65 ranges->ResetChecksum(); |
| 64 if (ranges->checksum() != ranges_checksum) | 66 if (ranges->checksum() != ranges_checksum) |
| 65 return nullptr; | 67 return nullptr; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 HistogramSamples::Metadata samples_metadata; | 105 HistogramSamples::Metadata samples_metadata; |
| 104 HistogramSamples::Metadata logged_metadata; | 106 HistogramSamples::Metadata logged_metadata; |
| 105 | 107 |
| 106 // Space for the histogram name will be added during the actual allocation | 108 // Space for the histogram name will be added during the actual allocation |
| 107 // request. This must be the last field of the structure. A zero-size array | 109 // request. This must be the last field of the structure. A zero-size array |
| 108 // or a "flexible" array would be preferred but is not (yet) valid C++. | 110 // or a "flexible" array would be preferred but is not (yet) valid C++. |
| 109 char name[1]; | 111 char name[1]; |
| 110 }; | 112 }; |
| 111 | 113 |
| 112 PersistentHistogramAllocator::PersistentHistogramAllocator( | 114 PersistentHistogramAllocator::PersistentHistogramAllocator( |
| 113 scoped_ptr<PersistentMemoryAllocator> memory) | 115 std::unique_ptr<PersistentMemoryAllocator> memory) |
| 114 : memory_allocator_(std::move(memory)) {} | 116 : memory_allocator_(std::move(memory)) {} |
| 115 | 117 |
| 116 PersistentHistogramAllocator::~PersistentHistogramAllocator() {} | 118 PersistentHistogramAllocator::~PersistentHistogramAllocator() {} |
| 117 | 119 |
| 118 void PersistentHistogramAllocator::CreateIterator(Iterator* iter) { | 120 void PersistentHistogramAllocator::CreateIterator(Iterator* iter) { |
| 119 memory_allocator_->CreateIterator(&iter->memory_iter); | 121 memory_allocator_->CreateIterator(&iter->memory_iter); |
| 120 } | 122 } |
| 121 | 123 |
| 122 void PersistentHistogramAllocator::CreateTrackingHistograms(StringPiece name) { | 124 void PersistentHistogramAllocator::CreateTrackingHistograms(StringPiece name) { |
| 123 memory_allocator_->CreateTrackingHistograms(name); | 125 memory_allocator_->CreateTrackingHistograms(name); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 167 // static | 169 // static |
| 168 void PersistentHistogramAllocator::RecordCreateHistogramResult( | 170 void PersistentHistogramAllocator::RecordCreateHistogramResult( |
| 169 CreateHistogramResultType result) { | 171 CreateHistogramResultType result) { |
| 170 HistogramBase* result_histogram = GetCreateHistogramResultHistogram(); | 172 HistogramBase* result_histogram = GetCreateHistogramResultHistogram(); |
| 171 if (result_histogram) | 173 if (result_histogram) |
| 172 result_histogram->Add(result); | 174 result_histogram->Add(result); |
| 173 } | 175 } |
| 174 | 176 |
| 175 // static | 177 // static |
| 176 void PersistentHistogramAllocator::SetGlobalAllocator( | 178 void PersistentHistogramAllocator::SetGlobalAllocator( |
| 177 scoped_ptr<PersistentHistogramAllocator> allocator) { | 179 std::unique_ptr<PersistentHistogramAllocator> allocator) { |
| 178 // Releasing or changing an allocator is extremely dangerous because it | 180 // Releasing or changing an allocator is extremely dangerous because it |
| 179 // likely has histograms stored within it. If the backing memory is also | 181 // likely has histograms stored within it. If the backing memory is also |
| 180 // also released, future accesses to those histograms will seg-fault. | 182 // also released, future accesses to those histograms will seg-fault. |
| 181 CHECK(!g_allocator); | 183 CHECK(!g_allocator); |
| 182 g_allocator = allocator.release(); | 184 g_allocator = allocator.release(); |
| 183 | 185 |
| 184 size_t existing = StatisticsRecorder::GetHistogramCount(); | 186 size_t existing = StatisticsRecorder::GetHistogramCount(); |
| 185 DLOG_IF(WARNING, existing) | 187 DLOG_IF(WARNING, existing) |
| 186 << existing | 188 << existing |
| 187 << " histograms were created before persistence was enabled."; | 189 << " histograms were created before persistence was enabled."; |
| 188 } | 190 } |
| 189 | 191 |
| 190 // static | 192 // static |
| 191 PersistentHistogramAllocator* | 193 PersistentHistogramAllocator* |
| 192 PersistentHistogramAllocator::GetGlobalAllocator() { | 194 PersistentHistogramAllocator::GetGlobalAllocator() { |
| 193 return g_allocator; | 195 return g_allocator; |
| 194 } | 196 } |
| 195 | 197 |
| 196 // static | 198 // static |
| 197 scoped_ptr<PersistentHistogramAllocator> | 199 std::unique_ptr<PersistentHistogramAllocator> |
| 198 PersistentHistogramAllocator::ReleaseGlobalAllocatorForTesting() { | 200 PersistentHistogramAllocator::ReleaseGlobalAllocatorForTesting() { |
| 199 PersistentHistogramAllocator* histogram_allocator = g_allocator; | 201 PersistentHistogramAllocator* histogram_allocator = g_allocator; |
| 200 if (!histogram_allocator) | 202 if (!histogram_allocator) |
| 201 return nullptr; | 203 return nullptr; |
| 202 PersistentMemoryAllocator* memory_allocator = | 204 PersistentMemoryAllocator* memory_allocator = |
| 203 histogram_allocator->memory_allocator(); | 205 histogram_allocator->memory_allocator(); |
| 204 | 206 |
| 205 // Before releasing the memory, it's necessary to have the Statistics- | 207 // Before releasing the memory, it's necessary to have the Statistics- |
| 206 // Recorder forget about the histograms contained therein; otherwise, | 208 // Recorder forget about the histograms contained therein; otherwise, |
| 207 // some operations will try to access them and the released memory. | 209 // some operations will try to access them and the released memory. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 222 // If that memory segment were to be deleted, future calls to create | 224 // If that memory segment were to be deleted, future calls to create |
| 223 // persistent histograms would crash. To avoid this, have the test call | 225 // persistent histograms would crash. To avoid this, have the test call |
| 224 // the method GetCreateHistogramResultHistogram() *before* setting | 226 // the method GetCreateHistogramResultHistogram() *before* setting |
| 225 // the (temporary) memory allocator via SetGlobalAllocator() so that | 227 // the (temporary) memory allocator via SetGlobalAllocator() so that |
| 226 // histogram is instead allocated from the process heap. | 228 // histogram is instead allocated from the process heap. |
| 227 DCHECK_NE(kResultHistogram, histogram_data->name); | 229 DCHECK_NE(kResultHistogram, histogram_data->name); |
| 228 } | 230 } |
| 229 } | 231 } |
| 230 | 232 |
| 231 g_allocator = nullptr; | 233 g_allocator = nullptr; |
| 232 return make_scoped_ptr(histogram_allocator); | 234 return base::WrapUnique(histogram_allocator); |
| 233 }; | 235 }; |
| 234 | 236 |
| 235 // static | 237 // static |
| 236 void PersistentHistogramAllocator::CreateGlobalAllocatorOnPersistentMemory( | 238 void PersistentHistogramAllocator::CreateGlobalAllocatorOnPersistentMemory( |
| 237 void* base, | 239 void* base, |
| 238 size_t size, | 240 size_t size, |
| 239 size_t page_size, | 241 size_t page_size, |
| 240 uint64_t id, | 242 uint64_t id, |
| 241 StringPiece name) { | 243 StringPiece name) { |
| 242 SetGlobalAllocator(make_scoped_ptr(new PersistentHistogramAllocator( | 244 SetGlobalAllocator(base::WrapUnique(new PersistentHistogramAllocator( |
| 243 make_scoped_ptr(new PersistentMemoryAllocator( | 245 base::WrapUnique(new PersistentMemoryAllocator(base, size, page_size, id, |
| 244 base, size, page_size, id, name, false))))); | 246 name, false))))); |
| 245 } | 247 } |
| 246 | 248 |
| 247 // static | 249 // static |
| 248 void PersistentHistogramAllocator::CreateGlobalAllocatorOnLocalMemory( | 250 void PersistentHistogramAllocator::CreateGlobalAllocatorOnLocalMemory( |
| 249 size_t size, | 251 size_t size, |
| 250 uint64_t id, | 252 uint64_t id, |
| 251 StringPiece name) { | 253 StringPiece name) { |
| 252 SetGlobalAllocator(make_scoped_ptr(new PersistentHistogramAllocator( | 254 SetGlobalAllocator(base::WrapUnique(new PersistentHistogramAllocator( |
| 253 make_scoped_ptr(new LocalPersistentMemoryAllocator(size, id, name))))); | 255 base::WrapUnique(new LocalPersistentMemoryAllocator(size, id, name))))); |
| 254 } | 256 } |
| 255 | 257 |
| 256 // static | 258 // static |
| 257 void PersistentHistogramAllocator::CreateGlobalAllocatorOnSharedMemory( | 259 void PersistentHistogramAllocator::CreateGlobalAllocatorOnSharedMemory( |
| 258 size_t size, | 260 size_t size, |
| 259 const SharedMemoryHandle& handle) { | 261 const SharedMemoryHandle& handle) { |
| 260 scoped_ptr<SharedMemory> shm(new SharedMemory(handle, /*readonly=*/false)); | 262 std::unique_ptr<SharedMemory> shm( |
| 263 new SharedMemory(handle, /*readonly=*/false)); |
| 261 if (!shm->Map(size)) { | 264 if (!shm->Map(size)) { |
| 262 NOTREACHED(); | 265 NOTREACHED(); |
| 263 return; | 266 return; |
| 264 } | 267 } |
| 265 | 268 |
| 266 SetGlobalAllocator(make_scoped_ptr(new PersistentHistogramAllocator( | 269 SetGlobalAllocator(base::WrapUnique(new PersistentHistogramAllocator( |
| 267 make_scoped_ptr(new SharedPersistentMemoryAllocator( | 270 base::WrapUnique(new SharedPersistentMemoryAllocator( |
| 268 std::move(shm), 0, StringPiece(), /*readonly=*/false))))); | 271 std::move(shm), 0, StringPiece(), /*readonly=*/false))))); |
| 269 } | 272 } |
| 270 | 273 |
| 271 // static | 274 // static |
| 272 scoped_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram( | 275 std::unique_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram( |
| 273 PersistentHistogramData* histogram_data_ptr) { | 276 PersistentHistogramData* histogram_data_ptr) { |
| 274 if (!histogram_data_ptr) { | 277 if (!histogram_data_ptr) { |
| 275 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER); | 278 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER); |
| 276 NOTREACHED(); | 279 NOTREACHED(); |
| 277 return nullptr; | 280 return nullptr; |
| 278 } | 281 } |
| 279 | 282 |
| 280 // Sparse histograms are quite different so handle them as a special case. | 283 // Sparse histograms are quite different so handle them as a special case. |
| 281 if (histogram_data_ptr->histogram_type == SPARSE_HISTOGRAM) { | 284 if (histogram_data_ptr->histogram_type == SPARSE_HISTOGRAM) { |
| 282 scoped_ptr<HistogramBase> histogram = SparseHistogram::PersistentCreate( | 285 std::unique_ptr<HistogramBase> histogram = |
| 283 memory_allocator(), histogram_data_ptr->name, | 286 SparseHistogram::PersistentCreate(memory_allocator(), |
| 284 &histogram_data_ptr->samples_metadata, | 287 histogram_data_ptr->name, |
| 285 &histogram_data_ptr->logged_metadata); | 288 &histogram_data_ptr->samples_metadata, |
| 289 &histogram_data_ptr->logged_metadata); |
| 286 DCHECK(histogram); | 290 DCHECK(histogram); |
| 287 histogram->SetFlags(histogram_data_ptr->flags); | 291 histogram->SetFlags(histogram_data_ptr->flags); |
| 288 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS); | 292 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS); |
| 289 return histogram; | 293 return histogram; |
| 290 } | 294 } |
| 291 | 295 |
| 292 // Copy the histogram_data to local storage because anything in persistent | 296 // Copy the histogram_data to local storage because anything in persistent |
| 293 // memory cannot be trusted as it could be changed at any moment by a | 297 // memory cannot be trusted as it could be changed at any moment by a |
| 294 // malicious actor that shares access. The contents of histogram_data are | 298 // malicious actor that shares access. The contents of histogram_data are |
| 295 // validated below; the local copy is to ensure that the contents cannot | 299 // validated below; the local copy is to ensure that the contents cannot |
| (...skipping 11 matching lines...) Expand all Loading... |
| 307 size_t allocated_bytes = | 311 size_t allocated_bytes = |
| 308 memory_allocator_->GetAllocSize(histogram_data.ranges_ref); | 312 memory_allocator_->GetAllocSize(histogram_data.ranges_ref); |
| 309 if (!ranges_data || histogram_data.bucket_count < 2 || | 313 if (!ranges_data || histogram_data.bucket_count < 2 || |
| 310 histogram_data.bucket_count >= max_buckets || | 314 histogram_data.bucket_count >= max_buckets || |
| 311 allocated_bytes < required_bytes) { | 315 allocated_bytes < required_bytes) { |
| 312 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); | 316 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); |
| 313 NOTREACHED(); | 317 NOTREACHED(); |
| 314 return nullptr; | 318 return nullptr; |
| 315 } | 319 } |
| 316 | 320 |
| 317 scoped_ptr<const BucketRanges> created_ranges = | 321 std::unique_ptr<const BucketRanges> created_ranges = |
| 318 CreateRangesFromData(ranges_data, histogram_data.ranges_checksum, | 322 CreateRangesFromData(ranges_data, histogram_data.ranges_checksum, |
| 319 histogram_data.bucket_count + 1); | 323 histogram_data.bucket_count + 1); |
| 320 if (!created_ranges) { | 324 if (!created_ranges) { |
| 321 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); | 325 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); |
| 322 NOTREACHED(); | 326 NOTREACHED(); |
| 323 return nullptr; | 327 return nullptr; |
| 324 } | 328 } |
| 325 const BucketRanges* ranges = | 329 const BucketRanges* ranges = |
| 326 StatisticsRecorder::RegisterOrDeleteDuplicateRanges( | 330 StatisticsRecorder::RegisterOrDeleteDuplicateRanges( |
| 327 created_ranges.release()); | 331 created_ranges.release()); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 339 return nullptr; | 343 return nullptr; |
| 340 } | 344 } |
| 341 | 345 |
| 342 // After the main "counts" array is a second array using for storing what | 346 // After the main "counts" array is a second array using for storing what |
| 343 // was previously logged. This is used to calculate the "delta" during | 347 // was previously logged. This is used to calculate the "delta" during |
| 344 // snapshot operations. | 348 // snapshot operations. |
| 345 HistogramBase::AtomicCount* logged_data = | 349 HistogramBase::AtomicCount* logged_data = |
| 346 counts_data + histogram_data.bucket_count; | 350 counts_data + histogram_data.bucket_count; |
| 347 | 351 |
| 348 std::string name(histogram_data_ptr->name); | 352 std::string name(histogram_data_ptr->name); |
| 349 scoped_ptr<HistogramBase> histogram; | 353 std::unique_ptr<HistogramBase> histogram; |
| 350 switch (histogram_data.histogram_type) { | 354 switch (histogram_data.histogram_type) { |
| 351 case HISTOGRAM: | 355 case HISTOGRAM: |
| 352 histogram = Histogram::PersistentCreate( | 356 histogram = Histogram::PersistentCreate( |
| 353 name, histogram_data.minimum, histogram_data.maximum, ranges, | 357 name, histogram_data.minimum, histogram_data.maximum, ranges, |
| 354 counts_data, logged_data, histogram_data.bucket_count, | 358 counts_data, logged_data, histogram_data.bucket_count, |
| 355 &histogram_data_ptr->samples_metadata, | 359 &histogram_data_ptr->samples_metadata, |
| 356 &histogram_data_ptr->logged_metadata); | 360 &histogram_data_ptr->logged_metadata); |
| 357 DCHECK(histogram); | 361 DCHECK(histogram); |
| 358 break; | 362 break; |
| 359 case LINEAR_HISTOGRAM: | 363 case LINEAR_HISTOGRAM: |
| (...skipping 26 matching lines...) Expand all Loading... |
| 386 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); | 390 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); |
| 387 histogram->SetFlags(histogram_data.flags); | 391 histogram->SetFlags(histogram_data.flags); |
| 388 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS); | 392 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS); |
| 389 } else { | 393 } else { |
| 390 RecordCreateHistogramResult(CREATE_HISTOGRAM_UNKNOWN_TYPE); | 394 RecordCreateHistogramResult(CREATE_HISTOGRAM_UNKNOWN_TYPE); |
| 391 } | 395 } |
| 392 | 396 |
| 393 return histogram; | 397 return histogram; |
| 394 } | 398 } |
| 395 | 399 |
| 396 scoped_ptr<HistogramBase> PersistentHistogramAllocator::GetHistogram( | 400 std::unique_ptr<HistogramBase> PersistentHistogramAllocator::GetHistogram( |
| 397 Reference ref) { | 401 Reference ref) { |
| 398 // Unfortunately, the histogram "pickle" methods cannot be used as part of | 402 // Unfortunately, the histogram "pickle" methods cannot be used as part of |
| 399 // the persistance because the deserialization methods always create local | 403 // the persistance because the deserialization methods always create local |
| 400 // count data (while these must reference the persistent counts) and always | 404 // count data (while these must reference the persistent counts) and always |
| 401 // add it to the local list of known histograms (while these may be simple | 405 // add it to the local list of known histograms (while these may be simple |
| 402 // references to histograms in other processes). | 406 // references to histograms in other processes). |
| 403 PersistentHistogramData* histogram_data = | 407 PersistentHistogramData* histogram_data = |
| 404 memory_allocator_->GetAsObject<PersistentHistogramData>( | 408 memory_allocator_->GetAsObject<PersistentHistogramData>( |
| 405 ref, kTypeIdHistogram); | 409 ref, kTypeIdHistogram); |
| 406 size_t length = memory_allocator_->GetAllocSize(ref); | 410 size_t length = memory_allocator_->GetAllocSize(ref); |
| 407 if (!histogram_data || | 411 if (!histogram_data || |
| 408 reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') { | 412 reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') { |
| 409 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA); | 413 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA); |
| 410 NOTREACHED(); | 414 NOTREACHED(); |
| 411 return nullptr; | 415 return nullptr; |
| 412 } | 416 } |
| 413 return CreateHistogram(histogram_data); | 417 return CreateHistogram(histogram_data); |
| 414 } | 418 } |
| 415 | 419 |
| 416 scoped_ptr<HistogramBase> | 420 std::unique_ptr<HistogramBase> |
| 417 PersistentHistogramAllocator::GetNextHistogramWithIgnore(Iterator* iter, | 421 PersistentHistogramAllocator::GetNextHistogramWithIgnore(Iterator* iter, |
| 418 Reference ignore) { | 422 Reference ignore) { |
| 419 PersistentMemoryAllocator::Reference ref; | 423 PersistentMemoryAllocator::Reference ref; |
| 420 uint32_t type_id; | 424 uint32_t type_id; |
| 421 while ((ref = memory_allocator_->GetNextIterable(&iter->memory_iter, | 425 while ((ref = memory_allocator_->GetNextIterable(&iter->memory_iter, |
| 422 &type_id)) != 0) { | 426 &type_id)) != 0) { |
| 423 if (ref == ignore) | 427 if (ref == ignore) |
| 424 continue; | 428 continue; |
| 425 if (type_id == kTypeIdHistogram) | 429 if (type_id == kTypeIdHistogram) |
| 426 return GetHistogram(ref); | 430 return GetHistogram(ref); |
| 427 } | 431 } |
| 428 return nullptr; | 432 return nullptr; |
| 429 } | 433 } |
| 430 | 434 |
| 431 void PersistentHistogramAllocator::FinalizeHistogram(Reference ref, | 435 void PersistentHistogramAllocator::FinalizeHistogram(Reference ref, |
| 432 bool registered) { | 436 bool registered) { |
| 433 // If the created persistent histogram was registered then it needs to | 437 // If the created persistent histogram was registered then it needs to |
| 434 // be marked as "iterable" in order to be found by other processes. | 438 // be marked as "iterable" in order to be found by other processes. |
| 435 if (registered) | 439 if (registered) |
| 436 memory_allocator_->MakeIterable(ref); | 440 memory_allocator_->MakeIterable(ref); |
| 437 // If it wasn't registered then a race condition must have caused | 441 // If it wasn't registered then a race condition must have caused |
| 438 // two to be created. The allocator does not support releasing the | 442 // two to be created. The allocator does not support releasing the |
| 439 // acquired memory so just change the type to be empty. | 443 // acquired memory so just change the type to be empty. |
| 440 else | 444 else |
| 441 memory_allocator_->SetType(ref, 0); | 445 memory_allocator_->SetType(ref, 0); |
| 442 } | 446 } |
| 443 | 447 |
| 444 scoped_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram( | 448 std::unique_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram( |
| 445 HistogramType histogram_type, | 449 HistogramType histogram_type, |
| 446 const std::string& name, | 450 const std::string& name, |
| 447 int minimum, | 451 int minimum, |
| 448 int maximum, | 452 int maximum, |
| 449 const BucketRanges* bucket_ranges, | 453 const BucketRanges* bucket_ranges, |
| 450 int32_t flags, | 454 int32_t flags, |
| 451 Reference* ref_ptr) { | 455 Reference* ref_ptr) { |
| 452 // If the allocator is corrupt, don't waste time trying anything else. | 456 // If the allocator is corrupt, don't waste time trying anything else. |
| 453 // This also allows differentiating on the dashboard between allocations | 457 // This also allows differentiating on the dashboard between allocations |
| 454 // failed due to a corrupt allocator and the number of process instances | 458 // failed due to a corrupt allocator and the number of process instances |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 514 histogram_data = nullptr; // Clear this for proper handling below. | 518 histogram_data = nullptr; // Clear this for proper handling below. |
| 515 } | 519 } |
| 516 } | 520 } |
| 517 | 521 |
| 518 if (histogram_data) { | 522 if (histogram_data) { |
| 519 // Create the histogram using resources in persistent memory. This ends up | 523 // Create the histogram using resources in persistent memory. This ends up |
| 520 // resolving the "ref" values stored in histogram_data instad of just | 524 // resolving the "ref" values stored in histogram_data instad of just |
| 521 // using what is already known above but avoids duplicating the switch | 525 // using what is already known above but avoids duplicating the switch |
| 522 // statement here and serves as a double-check that everything is | 526 // statement here and serves as a double-check that everything is |
| 523 // correct before commiting the new histogram to persistent space. | 527 // correct before commiting the new histogram to persistent space. |
| 524 scoped_ptr<HistogramBase> histogram = CreateHistogram(histogram_data); | 528 std::unique_ptr<HistogramBase> histogram = CreateHistogram(histogram_data); |
| 525 DCHECK(histogram); | 529 DCHECK(histogram); |
| 526 if (ref_ptr != nullptr) | 530 if (ref_ptr != nullptr) |
| 527 *ref_ptr = histogram_ref; | 531 *ref_ptr = histogram_ref; |
| 528 | 532 |
| 529 // By storing the reference within the allocator to this histogram, the | 533 // By storing the reference within the allocator to this histogram, the |
| 530 // next import (which will happen before the next histogram creation) | 534 // next import (which will happen before the next histogram creation) |
| 531 // will know to skip it. See also the comment in ImportGlobalHistograms(). | 535 // will know to skip it. See also the comment in ImportGlobalHistograms(). |
| 532 subtle::NoBarrier_Store(&last_created_, histogram_ref); | 536 subtle::NoBarrier_Store(&last_created_, histogram_ref); |
| 533 return histogram; | 537 return histogram; |
| 534 } | 538 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 568 // Skip the import if it's the histogram that was last created. Should a | 572 // Skip the import if it's the histogram that was last created. Should a |
| 569 // race condition cause the "last created" to be overwritten before it | 573 // race condition cause the "last created" to be overwritten before it |
| 570 // is recognized here then the histogram will be created and be ignored | 574 // is recognized here then the histogram will be created and be ignored |
| 571 // when it is detected as a duplicate by the statistics-recorder. This | 575 // when it is detected as a duplicate by the statistics-recorder. This |
| 572 // simple check reduces the time of creating persistent histograms by | 576 // simple check reduces the time of creating persistent histograms by |
| 573 // about 40%. | 577 // about 40%. |
| 574 Reference last_created = | 578 Reference last_created = |
| 575 subtle::NoBarrier_Load(&g_allocator->last_created_); | 579 subtle::NoBarrier_Load(&g_allocator->last_created_); |
| 576 | 580 |
| 577 while (true) { | 581 while (true) { |
| 578 scoped_ptr<HistogramBase> histogram = | 582 std::unique_ptr<HistogramBase> histogram = |
| 579 g_allocator->GetNextHistogramWithIgnore(&iter, last_created); | 583 g_allocator->GetNextHistogramWithIgnore(&iter, last_created); |
| 580 if (!histogram) | 584 if (!histogram) |
| 581 break; | 585 break; |
| 582 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); | 586 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); |
| 583 } | 587 } |
| 584 } | 588 } |
| 585 } | 589 } |
| 586 | 590 |
| 587 } // namespace base | 591 } // namespace base |
| OLD | NEW |