OLD | NEW |
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 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/histogram_persistence.h" | 5 #include "base/metrics/histogram_persistence.h" |
6 | 6 |
7 #include "base/lazy_instance.h" | 7 #include "base/lazy_instance.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 // (temporary) memory allocator via SetPersistentMemoryAllocator() so | 221 // (temporary) memory allocator via SetPersistentMemoryAllocator() so |
222 // that the histogram is instead allocated from the process heap. | 222 // that the histogram is instead allocated from the process heap. |
223 DCHECK_NE(kResultHistogram, histogram_data->name); | 223 DCHECK_NE(kResultHistogram, histogram_data->name); |
224 } | 224 } |
225 } | 225 } |
226 | 226 |
227 g_allocator = nullptr; | 227 g_allocator = nullptr; |
228 return allocator; | 228 return allocator; |
229 }; | 229 }; |
230 | 230 |
231 HistogramBase* CreatePersistentHistogram( | 231 scoped_ptr<HistogramBase> CreatePersistentHistogram( |
232 PersistentMemoryAllocator* allocator, | 232 PersistentMemoryAllocator* allocator, |
233 PersistentHistogramData* histogram_data_ptr) { | 233 PersistentHistogramData* histogram_data_ptr) { |
234 if (!histogram_data_ptr) { | 234 if (!histogram_data_ptr) { |
235 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER); | 235 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER); |
236 NOTREACHED(); | 236 NOTREACHED(); |
237 return nullptr; | 237 return nullptr; |
238 } | 238 } |
239 | 239 |
240 // Copy the histogram_data to local storage because anything in persistent | 240 // Copy the histogram_data to local storage because anything in persistent |
241 // memory cannot be trusted as it could be changed at any moment by a | 241 // memory cannot be trusted as it could be changed at any moment by a |
242 // malicious actor that shares access. The contents of histogram_data are | 242 // malicious actor that shares access. The contents of histogram_data are |
243 // validated below; the local copy is to ensure that the contents cannot | 243 // validated below; the local copy is to ensure that the contents cannot |
244 // be externally changed between validation and use. | 244 // be externally changed between validation and use. |
245 PersistentHistogramData histogram_data = *histogram_data_ptr; | 245 PersistentHistogramData histogram_data = *histogram_data_ptr; |
246 | 246 |
247 HistogramBase::Sample* ranges_data = | 247 HistogramBase::Sample* ranges_data = |
248 allocator->GetAsObject<HistogramBase::Sample>(histogram_data.ranges_ref, | 248 allocator->GetAsObject<HistogramBase::Sample>(histogram_data.ranges_ref, |
249 kTypeIdRangesArray); | 249 kTypeIdRangesArray); |
250 if (!ranges_data || histogram_data.bucket_count < 2 || | 250 if (!ranges_data || histogram_data.bucket_count < 2 || |
251 histogram_data.bucket_count + 1 > | 251 histogram_data.bucket_count + 1 > |
252 std::numeric_limits<uint32_t>::max() / | 252 std::numeric_limits<uint32_t>::max() / |
253 sizeof(HistogramBase::Sample) || | 253 sizeof(HistogramBase::Sample) || |
254 allocator->GetAllocSize(histogram_data.ranges_ref) < | 254 allocator->GetAllocSize(histogram_data.ranges_ref) < |
255 (histogram_data.bucket_count + 1) * sizeof(HistogramBase::Sample)) { | 255 (histogram_data.bucket_count + 1) * sizeof(HistogramBase::Sample)) { |
256 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); | 256 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); |
257 NOTREACHED(); | 257 NOTREACHED(); |
258 return nullptr; | 258 return nullptr; |
259 } | 259 } |
260 // To avoid racy destruction at shutdown, the following will be leaked. | 260 |
261 const BucketRanges* ranges = CreateRangesFromData( | 261 scoped_ptr<const BucketRanges> created_ranges(CreateRangesFromData( |
262 ranges_data, | 262 ranges_data, |
263 histogram_data.ranges_checksum, | 263 histogram_data.ranges_checksum, |
264 histogram_data.bucket_count + 1); | 264 histogram_data.bucket_count + 1)); |
265 if (!ranges) { | 265 if (!created_ranges) { |
266 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); | 266 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); |
267 NOTREACHED(); | 267 NOTREACHED(); |
268 return nullptr; | 268 return nullptr; |
269 } | 269 } |
270 ranges = StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 270 const BucketRanges* ranges = |
| 271 StatisticsRecorder::RegisterOrDeleteDuplicateRanges( |
| 272 std::move(created_ranges)); |
271 | 273 |
272 HistogramBase::AtomicCount* counts_data = | 274 HistogramBase::AtomicCount* counts_data = |
273 allocator->GetAsObject<HistogramBase::AtomicCount>( | 275 allocator->GetAsObject<HistogramBase::AtomicCount>( |
274 histogram_data.counts_ref, kTypeIdCountsArray); | 276 histogram_data.counts_ref, kTypeIdCountsArray); |
275 size_t counts_bytes = | 277 size_t counts_bytes = |
276 CalculateRequiredCountsBytes(histogram_data.bucket_count); | 278 CalculateRequiredCountsBytes(histogram_data.bucket_count); |
277 if (!counts_data || !counts_bytes || | 279 if (!counts_data || !counts_bytes || |
278 allocator->GetAllocSize(histogram_data.counts_ref) < counts_bytes) { | 280 allocator->GetAllocSize(histogram_data.counts_ref) < counts_bytes) { |
279 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY); | 281 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY); |
280 NOTREACHED(); | 282 NOTREACHED(); |
281 return nullptr; | 283 return nullptr; |
282 } | 284 } |
283 | 285 |
284 // After the main "counts" array is a second array using for storing what | 286 // After the main "counts" array is a second array using for storing what |
285 // was previously logged. This is used to calculate the "delta" during | 287 // was previously logged. This is used to calculate the "delta" during |
286 // snapshot operations. | 288 // snapshot operations. |
287 HistogramBase::AtomicCount* logged_data = | 289 HistogramBase::AtomicCount* logged_data = |
288 counts_data + histogram_data.bucket_count; | 290 counts_data + histogram_data.bucket_count; |
289 | 291 |
290 std::string name(histogram_data_ptr->name); | 292 std::string name(histogram_data_ptr->name); |
291 HistogramBase* histogram = nullptr; | 293 scoped_ptr<HistogramBase> histogram; |
292 switch (histogram_data.histogram_type) { | 294 switch (histogram_data.histogram_type) { |
293 case HISTOGRAM: | 295 case HISTOGRAM: |
294 histogram = Histogram::PersistentGet( | 296 histogram.reset(Histogram::PersistentGet( |
295 name, | 297 name, |
296 histogram_data.minimum, | 298 histogram_data.minimum, |
297 histogram_data.maximum, | 299 histogram_data.maximum, |
298 ranges, | 300 ranges, |
299 counts_data, | 301 counts_data, |
300 logged_data, | 302 logged_data, |
301 histogram_data.bucket_count, | 303 histogram_data.bucket_count, |
302 &histogram_data_ptr->samples_metadata, | 304 &histogram_data_ptr->samples_metadata, |
303 &histogram_data_ptr->logged_metadata); | 305 &histogram_data_ptr->logged_metadata)); |
304 DCHECK(histogram); | 306 DCHECK(histogram); |
305 break; | 307 break; |
306 case LINEAR_HISTOGRAM: | 308 case LINEAR_HISTOGRAM: |
307 histogram = LinearHistogram::PersistentGet( | 309 histogram.reset(LinearHistogram::PersistentGet( |
308 name, | 310 name, |
309 histogram_data.minimum, | 311 histogram_data.minimum, |
310 histogram_data.maximum, | 312 histogram_data.maximum, |
311 ranges, | 313 ranges, |
312 counts_data, | 314 counts_data, |
313 logged_data, | 315 logged_data, |
314 histogram_data.bucket_count, | 316 histogram_data.bucket_count, |
315 &histogram_data_ptr->samples_metadata, | 317 &histogram_data_ptr->samples_metadata, |
316 &histogram_data_ptr->logged_metadata); | 318 &histogram_data_ptr->logged_metadata)); |
317 DCHECK(histogram); | 319 DCHECK(histogram); |
318 break; | 320 break; |
319 case BOOLEAN_HISTOGRAM: | 321 case BOOLEAN_HISTOGRAM: |
320 histogram = BooleanHistogram::PersistentGet( | 322 histogram.reset(BooleanHistogram::PersistentGet( |
321 name, | 323 name, |
322 ranges, | 324 ranges, |
323 counts_data, | 325 counts_data, |
324 logged_data, | 326 logged_data, |
325 &histogram_data_ptr->samples_metadata, | 327 &histogram_data_ptr->samples_metadata, |
326 &histogram_data_ptr->logged_metadata); | 328 &histogram_data_ptr->logged_metadata)); |
327 DCHECK(histogram); | 329 DCHECK(histogram); |
328 break; | 330 break; |
329 case CUSTOM_HISTOGRAM: | 331 case CUSTOM_HISTOGRAM: |
330 histogram = CustomHistogram::PersistentGet( | 332 histogram.reset(CustomHistogram::PersistentGet( |
331 name, | 333 name, |
332 ranges, | 334 ranges, |
333 counts_data, | 335 counts_data, |
334 logged_data, | 336 logged_data, |
335 histogram_data.bucket_count, | 337 histogram_data.bucket_count, |
336 &histogram_data_ptr->samples_metadata, | 338 &histogram_data_ptr->samples_metadata, |
337 &histogram_data_ptr->logged_metadata); | 339 &histogram_data_ptr->logged_metadata)); |
338 DCHECK(histogram); | 340 DCHECK(histogram); |
339 break; | 341 break; |
340 default: | 342 default: |
341 NOTREACHED(); | 343 NOTREACHED(); |
342 } | 344 } |
343 | 345 |
344 if (histogram) { | 346 if (histogram) { |
345 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); | 347 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); |
346 histogram->SetFlags(histogram_data.flags); | 348 histogram->SetFlags(histogram_data.flags); |
347 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS); | 349 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS); |
348 } else { | 350 } else { |
349 RecordCreateHistogramResult(CREATE_HISTOGRAM_UNKNOWN_TYPE); | 351 RecordCreateHistogramResult(CREATE_HISTOGRAM_UNKNOWN_TYPE); |
350 } | 352 } |
351 | 353 |
352 return histogram; | 354 return histogram; |
353 } | 355 } |
354 | 356 |
355 HistogramBase* GetPersistentHistogram( | 357 scoped_ptr<HistogramBase> GetPersistentHistogram( |
356 PersistentMemoryAllocator* allocator, | 358 PersistentMemoryAllocator* allocator, |
357 int32_t ref) { | 359 int32_t ref) { |
358 // Unfortunately, the above "pickle" methods cannot be used as part of the | 360 // Unfortunately, the above "pickle" methods cannot be used as part of the |
359 // persistance because the deserialization methods always create local | 361 // persistance because the deserialization methods always create local |
360 // count data (these must referenced the persistent counts) and always add | 362 // count data (these must referenced the persistent counts) and always add |
361 // it to the local list of known histograms (these may be simple references | 363 // it to the local list of known histograms (these may be simple references |
362 // to histograms in other processes). | 364 // to histograms in other processes). |
363 PersistentHistogramData* histogram_data = | 365 PersistentHistogramData* histogram_data = |
364 allocator->GetAsObject<PersistentHistogramData>(ref, kTypeIdHistogram); | 366 allocator->GetAsObject<PersistentHistogramData>(ref, kTypeIdHistogram); |
365 size_t length = allocator->GetAllocSize(ref); | 367 size_t length = allocator->GetAllocSize(ref); |
366 if (!histogram_data || | 368 if (!histogram_data || |
367 reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') { | 369 reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') { |
368 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA); | 370 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA); |
369 NOTREACHED(); | 371 NOTREACHED(); |
370 return nullptr; | 372 return nullptr; |
371 } | 373 } |
372 return CreatePersistentHistogram(allocator, histogram_data); | 374 return CreatePersistentHistogram(allocator, histogram_data); |
373 } | 375 } |
374 | 376 |
375 HistogramBase* GetNextPersistentHistogram( | 377 scoped_ptr<HistogramBase> GetNextPersistentHistogram( |
376 PersistentMemoryAllocator* allocator, | 378 PersistentMemoryAllocator* allocator, |
377 PersistentMemoryAllocator::Iterator* iter) { | 379 PersistentMemoryAllocator::Iterator* iter) { |
378 PersistentMemoryAllocator::Reference ref; | 380 PersistentMemoryAllocator::Reference ref; |
379 uint32_t type_id; | 381 uint32_t type_id; |
380 while ((ref = allocator->GetNextIterable(iter, &type_id)) != 0) { | 382 while ((ref = allocator->GetNextIterable(iter, &type_id)) != 0) { |
381 if (type_id == kTypeIdHistogram) | 383 if (type_id == kTypeIdHistogram) |
382 return GetPersistentHistogram(allocator, ref); | 384 return GetPersistentHistogram(allocator, ref); |
383 } | 385 } |
384 return nullptr; | 386 return nullptr; |
385 } | 387 } |
386 | 388 |
387 void FinalizePersistentHistogram(PersistentMemoryAllocator::Reference ref, | 389 void FinalizePersistentHistogram(PersistentMemoryAllocator::Reference ref, |
388 bool registered) { | 390 bool registered) { |
389 // If the created persistent histogram was registered then it needs to | 391 // If the created persistent histogram was registered then it needs to |
390 // be marked as "iterable" in order to be found by other processes. | 392 // be marked as "iterable" in order to be found by other processes. |
391 if (registered) | 393 if (registered) |
392 GetPersistentHistogramMemoryAllocator()->MakeIterable(ref); | 394 GetPersistentHistogramMemoryAllocator()->MakeIterable(ref); |
393 // If it wasn't registered then a race condition must have caused | 395 // If it wasn't registered then a race condition must have caused |
394 // two to be created. The allocator does not support releasing the | 396 // two to be created. The allocator does not support releasing the |
395 // acquired memory so just change the type to be empty. | 397 // acquired memory so just change the type to be empty. |
396 else | 398 else |
397 GetPersistentHistogramMemoryAllocator()->SetType(ref, 0); | 399 GetPersistentHistogramMemoryAllocator()->SetType(ref, 0); |
398 } | 400 } |
399 | 401 |
400 HistogramBase* AllocatePersistentHistogram( | 402 scoped_ptr<HistogramBase> AllocatePersistentHistogram( |
401 PersistentMemoryAllocator* allocator, | 403 PersistentMemoryAllocator* allocator, |
402 HistogramType histogram_type, | 404 HistogramType histogram_type, |
403 const std::string& name, | 405 const std::string& name, |
404 int minimum, | 406 int minimum, |
405 int maximum, | 407 int maximum, |
406 const BucketRanges* bucket_ranges, | 408 const BucketRanges* bucket_ranges, |
407 int32_t flags, | 409 int32_t flags, |
408 PersistentMemoryAllocator::Reference* ref_ptr) { | 410 PersistentMemoryAllocator::Reference* ref_ptr) { |
409 if (!allocator) | 411 if (!allocator) |
410 return nullptr; | 412 return nullptr; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 histogram_data->bucket_count = static_cast<uint32_t>(bucket_count); | 460 histogram_data->bucket_count = static_cast<uint32_t>(bucket_count); |
459 histogram_data->ranges_ref = ranges_ref; | 461 histogram_data->ranges_ref = ranges_ref; |
460 histogram_data->ranges_checksum = bucket_ranges->checksum(); | 462 histogram_data->ranges_checksum = bucket_ranges->checksum(); |
461 histogram_data->counts_ref = counts_ref; | 463 histogram_data->counts_ref = counts_ref; |
462 | 464 |
463 // Create the histogram using resources in persistent memory. This ends up | 465 // Create the histogram using resources in persistent memory. This ends up |
464 // resolving the "ref" values stored in histogram_data instad of just | 466 // resolving the "ref" values stored in histogram_data instad of just |
465 // using what is already known above but avoids duplicating the switch | 467 // using what is already known above but avoids duplicating the switch |
466 // statement here and serves as a double-check that everything is | 468 // statement here and serves as a double-check that everything is |
467 // correct before commiting the new histogram to persistent space. | 469 // correct before commiting the new histogram to persistent space. |
468 HistogramBase* histogram = | 470 scoped_ptr<HistogramBase> histogram( |
469 CreatePersistentHistogram(allocator, histogram_data); | 471 CreatePersistentHistogram(allocator, histogram_data)); |
470 DCHECK(histogram); | 472 DCHECK(histogram); |
471 if (ref_ptr != nullptr) | 473 if (ref_ptr != nullptr) |
472 *ref_ptr = histogram_ref; | 474 *ref_ptr = histogram_ref; |
473 return histogram; | 475 return histogram; |
474 } | 476 } |
475 | 477 |
476 CreateHistogramResultType result; | 478 CreateHistogramResultType result; |
477 if (allocator->IsCorrupt()) { | 479 if (allocator->IsCorrupt()) { |
478 RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT); | 480 RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT); |
479 result = CREATE_HISTOGRAM_ALLOCATOR_CORRUPT; | 481 result = CREATE_HISTOGRAM_ALLOCATOR_CORRUPT; |
(...skipping 17 matching lines...) Expand all Loading... |
497 base::AutoLock auto_lock(lock.Get()); | 499 base::AutoLock auto_lock(lock.Get()); |
498 | 500 |
499 // Each call resumes from where it last left off so need persistant | 501 // Each call resumes from where it last left off so need persistant |
500 // iterator. This class has a constructor so even the definition has | 502 // iterator. This class has a constructor so even the definition has |
501 // to be protected by the lock in order to be thread-safe. | 503 // to be protected by the lock in order to be thread-safe. |
502 static PersistentMemoryAllocator::Iterator iter; | 504 static PersistentMemoryAllocator::Iterator iter; |
503 if (iter.is_clear()) | 505 if (iter.is_clear()) |
504 g_allocator->CreateIterator(&iter); | 506 g_allocator->CreateIterator(&iter); |
505 | 507 |
506 while (true) { | 508 while (true) { |
507 HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter); | 509 scoped_ptr<HistogramBase> histogram( |
| 510 GetNextPersistentHistogram(g_allocator, &iter)); |
508 if (!histogram) | 511 if (!histogram) |
509 break; | 512 break; |
510 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram); | 513 StatisticsRecorder::RegisterOrDeleteDuplicate(std::move(histogram)); |
511 } | 514 } |
512 } | 515 } |
513 } | 516 } |
514 | 517 |
515 } // namespace base | 518 } // namespace base |
OLD | NEW |