Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/tracked_objects.h" | 5 #include "base/tracked_objects.h" |
| 6 | 6 |
| 7 #include <ctype.h> | 7 #include <ctype.h> |
| 8 #include <limits.h> | 8 #include <limits.h> |
| 9 #include <stdlib.h> | 9 #include <stdlib.h> |
| 10 | 10 |
| 11 #include <limits> | |
| 12 | |
| 11 #include "base/atomicops.h" | 13 #include "base/atomicops.h" |
| 12 #include "base/base_switches.h" | 14 #include "base/base_switches.h" |
| 13 #include "base/command_line.h" | 15 #include "base/command_line.h" |
| 14 #include "base/compiler_specific.h" | 16 #include "base/compiler_specific.h" |
| 15 #include "base/debug/leak_annotations.h" | 17 #include "base/debug/leak_annotations.h" |
| 16 #include "base/logging.h" | 18 #include "base/logging.h" |
| 17 #include "base/metrics/histogram_macros.h" | 19 #include "base/metrics/histogram_macros.h" |
| 18 #include "base/numerics/safe_conversions.h" | 20 #include "base/numerics/safe_conversions.h" |
| 19 #include "base/numerics/safe_math.h" | 21 #include "base/numerics/safe_math.h" |
| 20 #include "base/process/process_handle.h" | 22 #include "base/process/process_handle.h" |
| 21 #include "base/third_party/valgrind/memcheck.h" | 23 #include "base/third_party/valgrind/memcheck.h" |
| 24 #include "base/threading/platform_thread.h" | |
| 22 #include "base/threading/worker_pool.h" | 25 #include "base/threading/worker_pool.h" |
| 23 #include "base/tracking_info.h" | 26 #include "base/tracking_info.h" |
| 24 #include "build/build_config.h" | 27 #include "build/build_config.h" |
| 25 | 28 |
| 26 using base::TimeDelta; | 29 using base::TimeDelta; |
| 27 | 30 |
| 28 namespace base { | 31 namespace base { |
| 29 class TimeDelta; | 32 class TimeDelta; |
| 30 } | 33 } |
| 31 | 34 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 103 | 106 |
| 104 DeathData::DeathData() | 107 DeathData::DeathData() |
| 105 : count_(0), | 108 : count_(0), |
| 106 sample_probability_count_(0), | 109 sample_probability_count_(0), |
| 107 run_duration_sum_(0), | 110 run_duration_sum_(0), |
| 108 queue_duration_sum_(0), | 111 queue_duration_sum_(0), |
| 109 run_duration_max_(0), | 112 run_duration_max_(0), |
| 110 queue_duration_max_(0), | 113 queue_duration_max_(0), |
| 111 alloc_ops_(0), | 114 alloc_ops_(0), |
| 112 free_ops_(0), | 115 free_ops_(0), |
| 113 allocated_bytes_(0), | 116 #if !defined(ARCH_CPU_64_BITS) |
| 114 freed_bytes_(0), | 117 byte_update_counter_(0), |
| 115 alloc_overhead_bytes_(0), | 118 #endif |
| 119 allocated_bytes_(), | |
| 120 freed_bytes_(), | |
| 121 alloc_overhead_bytes_(), | |
| 116 max_allocated_bytes_(0), | 122 max_allocated_bytes_(0), |
| 117 run_duration_sample_(0), | 123 run_duration_sample_(0), |
| 118 queue_duration_sample_(0), | 124 queue_duration_sample_(0), |
| 119 last_phase_snapshot_(nullptr) {} | 125 last_phase_snapshot_(nullptr) { |
| 126 } | |
| 120 | 127 |
| 121 DeathData::DeathData(const DeathData& other) | 128 DeathData::DeathData(const DeathData& other) |
| 122 : count_(other.count_), | 129 : count_(other.count_), |
| 123 sample_probability_count_(other.sample_probability_count_), | 130 sample_probability_count_(other.sample_probability_count_), |
| 124 run_duration_sum_(other.run_duration_sum_), | 131 run_duration_sum_(other.run_duration_sum_), |
| 125 queue_duration_sum_(other.queue_duration_sum_), | 132 queue_duration_sum_(other.queue_duration_sum_), |
| 126 run_duration_max_(other.run_duration_max_), | 133 run_duration_max_(other.run_duration_max_), |
| 127 queue_duration_max_(other.queue_duration_max_), | 134 queue_duration_max_(other.queue_duration_max_), |
| 128 alloc_ops_(other.alloc_ops_), | 135 alloc_ops_(other.alloc_ops_), |
| 129 free_ops_(other.free_ops_), | 136 free_ops_(other.free_ops_), |
| 137 #if !defined(ARCH_CPU_64_BITS) | |
| 138 byte_update_counter_(0), | |
| 139 #endif | |
| 130 allocated_bytes_(other.allocated_bytes_), | 140 allocated_bytes_(other.allocated_bytes_), |
| 131 freed_bytes_(other.freed_bytes_), | 141 freed_bytes_(other.freed_bytes_), |
| 132 alloc_overhead_bytes_(other.alloc_overhead_bytes_), | 142 alloc_overhead_bytes_(other.alloc_overhead_bytes_), |
| 133 max_allocated_bytes_(other.max_allocated_bytes_), | 143 max_allocated_bytes_(other.max_allocated_bytes_), |
| 134 run_duration_sample_(other.run_duration_sample_), | 144 run_duration_sample_(other.run_duration_sample_), |
| 135 queue_duration_sample_(other.queue_duration_sample_), | 145 queue_duration_sample_(other.queue_duration_sample_), |
| 136 last_phase_snapshot_(nullptr) { | 146 last_phase_snapshot_(nullptr) { |
| 137 // This constructor will be used by std::map when adding new DeathData values | 147 // This constructor will be used by std::map when adding new DeathData values |
| 138 // to the map. At that point, last_phase_snapshot_ is still NULL, so we don't | 148 // to the map. At that point, last_phase_snapshot_ is still NULL, so we don't |
| 139 // need to worry about ownership transfer. | 149 // need to worry about ownership transfer. |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 196 base::subtle::NoBarrier_Store(&run_duration_sample_, run_duration); | 206 base::subtle::NoBarrier_Store(&run_duration_sample_, run_duration); |
| 197 } | 207 } |
| 198 } | 208 } |
| 199 | 209 |
| 200 void DeathData::RecordAllocations(const uint32_t alloc_ops, | 210 void DeathData::RecordAllocations(const uint32_t alloc_ops, |
| 201 const uint32_t free_ops, | 211 const uint32_t free_ops, |
| 202 const uint32_t allocated_bytes, | 212 const uint32_t allocated_bytes, |
| 203 const uint32_t freed_bytes, | 213 const uint32_t freed_bytes, |
| 204 const uint32_t alloc_overhead_bytes, | 214 const uint32_t alloc_overhead_bytes, |
| 205 const uint32_t max_allocated_bytes) { | 215 const uint32_t max_allocated_bytes) { |
| 216 #if !defined(ARCH_CPU_64_BITS) | |
| 217 // On 32 bit systems, we use an even/odd locking scheme to make possible to | |
| 218 // read 64 bit sums consistently. Note that since writes are bound to the | |
| 219 // thread owning this DeathData, there's no race on these writes. | |
| 220 int32_t counter_val = | |
| 221 base::subtle::Barrier_AtomicIncrement(&byte_update_counter_, 1); | |
| 222 // The counter must be odd. | |
| 223 DCHECK_EQ(1, counter_val & 1); | |
| 224 #endif | |
| 225 | |
| 206 // Use saturating arithmetic. | 226 // Use saturating arithmetic. |
| 207 SaturatingMemberAdd(alloc_ops, &alloc_ops_); | 227 SaturatingMemberAdd(alloc_ops, &alloc_ops_); |
| 208 SaturatingMemberAdd(free_ops, &free_ops_); | 228 SaturatingMemberAdd(free_ops, &free_ops_); |
| 209 SaturatingMemberAdd(allocated_bytes, &allocated_bytes_); | 229 SaturatingByteCountMemberAdd(allocated_bytes, &allocated_bytes_); |
| 210 SaturatingMemberAdd(freed_bytes, &freed_bytes_); | 230 SaturatingByteCountMemberAdd(freed_bytes, &freed_bytes_); |
| 211 SaturatingMemberAdd(alloc_overhead_bytes, &alloc_overhead_bytes_); | 231 SaturatingByteCountMemberAdd(alloc_overhead_bytes, &alloc_overhead_bytes_); |
| 212 | 232 |
| 213 int32_t max = base::saturated_cast<int32_t>(max_allocated_bytes); | 233 int32_t max = base::saturated_cast<int32_t>(max_allocated_bytes); |
| 214 if (max > max_allocated_bytes_) | 234 if (max > max_allocated_bytes_) |
| 215 base::subtle::NoBarrier_Store(&max_allocated_bytes_, max); | 235 base::subtle::NoBarrier_Store(&max_allocated_bytes_, max); |
| 236 | |
| 237 #if !defined(ARCH_CPU_64_BITS) | |
| 238 // Now release the value while rolling to even. | |
| 239 counter_val = base::subtle::Barrier_AtomicIncrement(&byte_update_counter_, 1); | |
| 240 DCHECK_EQ(0, counter_val & 1); | |
| 241 #endif | |
| 216 } | 242 } |
| 217 | 243 |
| 218 void DeathData::OnProfilingPhaseCompleted(int profiling_phase) { | 244 void DeathData::OnProfilingPhaseCompleted(int profiling_phase) { |
| 219 // Snapshotting and storing current state. | 245 // Snapshotting and storing current state. |
| 220 last_phase_snapshot_ = | 246 last_phase_snapshot_ = |
| 221 new DeathDataPhaseSnapshot(profiling_phase, *this, last_phase_snapshot_); | 247 new DeathDataPhaseSnapshot(profiling_phase, *this, last_phase_snapshot_); |
| 222 | 248 |
| 223 // Not touching fields for which a delta can be computed by comparing with a | 249 // Not touching fields for which a delta can be computed by comparing with a |
| 224 // snapshot from the previous phase. Resetting other fields. Sample values | 250 // snapshot from the previous phase. Resetting other fields. Sample values |
| 225 // will be reset upon next death recording because sample_probability_count_ | 251 // will be reset upon next death recording because sample_probability_count_ |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 243 // The damage is limited to selecting a wrong sample, which is not something | 269 // The damage is limited to selecting a wrong sample, which is not something |
| 244 // that can cause accumulating or cascading effects. | 270 // that can cause accumulating or cascading effects. |
| 245 // If there were no inconsistencies caused by race conditions, we never send a | 271 // If there were no inconsistencies caused by race conditions, we never send a |
| 246 // sample for the previous phase in the next phase's snapshot because | 272 // sample for the previous phase in the next phase's snapshot because |
| 247 // ThreadData::SnapshotExecutedTasks doesn't send deltas with 0 count. | 273 // ThreadData::SnapshotExecutedTasks doesn't send deltas with 0 count. |
| 248 base::subtle::NoBarrier_Store(&sample_probability_count_, 0); | 274 base::subtle::NoBarrier_Store(&sample_probability_count_, 0); |
| 249 base::subtle::NoBarrier_Store(&run_duration_max_, 0); | 275 base::subtle::NoBarrier_Store(&run_duration_max_, 0); |
| 250 base::subtle::NoBarrier_Store(&queue_duration_max_, 0); | 276 base::subtle::NoBarrier_Store(&queue_duration_max_, 0); |
| 251 } | 277 } |
| 252 | 278 |
| 279 int64_t DeathData::CumulativeByteCountRead(const CumulativeByteCount* count) { | |
| 280 #if defined(ARCH_CPU_64_BITS) | |
| 281 return *count; | |
| 282 #else | |
| 283 return static_cast<int64_t>(count->hi_word) << 32 | | |
| 284 static_cast<uint32_t>(count->lo_word); | |
| 285 #endif | |
| 286 } | |
| 287 | |
| 288 int64_t DeathData::ConsistentCumulativeByteCountRead( | |
| 289 const CumulativeByteCount* count) const { | |
| 290 #if defined(ARCH_CPU_64_BITS) | |
| 291 return base::subtle::NoBarrier_Load(count); | |
| 292 #else | |
| 293 // We're on a 32 bit system, this is going to be complicated. | |
| 294 while (true) { | |
| 295 int32_t update_counter = 0; | |
| 296 // Acquire the starting count, spin until it's even. | |
| 297 | |
| 298 // The value of |kYieldProcessorTries| is cargo culted from the page | |
| 299 // allocator, TCMalloc, Window critical section defaults, and various other | |
| 300 // recommendations. | |
| 301 // This is not performance critical here, as the reads are vanishingly rare | |
| 302 // and only happen under the --enable-heap-profiling=task-profiler flag. | |
| 303 constexpr size_t kYieldProcessorTries = 10000; | |
|
gab
2017/05/03 17:25:37
spin_lock.cc uses 1000 not 10000
spin_lock.cc als
Sigurður Ásgeirsson
2017/05/03 17:44:04
Ugh, typo alert!
Lemme try it this way - like you
| |
| 304 size_t lock_attempts = 0; | |
| 305 do { | |
| 306 ++lock_attempts; | |
| 307 if (lock_attempts == kYieldProcessorTries) { | |
| 308 // Yield the current thread periodically to avoid writer starvation. | |
| 309 base::PlatformThread::YieldCurrentThread(); | |
| 310 lock_attempts = 0; | |
| 311 } | |
| 312 | |
| 313 update_counter = base::subtle::Acquire_Load(&byte_update_counter_); | |
|
gab
2017/05/03 17:25:37
optional:
After reading http://preshing.com/20130
Sigurður Ásgeirsson
2017/05/03 17:44:04
Done.
| |
| 314 } while (update_counter & 1); | |
| 315 | |
| 316 DCHECK_EQ(update_counter & 1, 0); | |
| 317 | |
| 318 int64_t value = | |
| 319 static_cast<int64_t>(base::subtle::NoBarrier_Load(&count->hi_word)) | |
| 320 << 32 | | |
| 321 static_cast<uint32_t>(base::subtle::NoBarrier_Load(&count->lo_word)); | |
| 322 | |
| 323 // If the count has not changed, the read is consistent. | |
| 324 // Otherwise go around and try again. | |
| 325 if (update_counter == base::subtle::Acquire_Load(&byte_update_counter_)) | |
|
gab
2017/05/03 17:25:37
Acquire semantics at the end of the method do noth
Sigurður Ásgeirsson
2017/05/03 17:44:04
Ah, cool, that makes sense.
| |
| 326 return value; | |
| 327 } | |
| 328 #endif | |
| 329 } | |
| 330 | |
| 253 void DeathData::SaturatingMemberAdd(const uint32_t addend, | 331 void DeathData::SaturatingMemberAdd(const uint32_t addend, |
| 254 base::subtle::Atomic32* sum) { | 332 base::subtle::Atomic32* sum) { |
| 333 constexpr int32_t kInt32Max = std::numeric_limits<int32_t>::max(); | |
| 255 // Bail quick if no work or already saturated. | 334 // Bail quick if no work or already saturated. |
| 256 if (addend == 0U || *sum == INT_MAX) | 335 if (addend == 0U || *sum == kInt32Max) |
| 257 return; | 336 return; |
| 258 | 337 |
| 259 base::CheckedNumeric<int32_t> new_sum = *sum; | 338 base::CheckedNumeric<int32_t> new_sum = *sum; |
| 260 new_sum += addend; | 339 new_sum += addend; |
| 261 base::subtle::NoBarrier_Store(sum, new_sum.ValueOrDefault(INT_MAX)); | 340 base::subtle::NoBarrier_Store(sum, new_sum.ValueOrDefault(kInt32Max)); |
| 341 } | |
| 342 | |
| 343 void DeathData::SaturatingByteCountMemberAdd(const uint32_t addend, | |
| 344 CumulativeByteCount* sum) { | |
| 345 constexpr int64_t kInt64Max = std::numeric_limits<int64_t>::max(); | |
| 346 // Bail quick if no work or already saturated. | |
| 347 if (addend == 0U || CumulativeByteCountRead(sum) == kInt64Max) | |
| 348 return; | |
| 349 | |
| 350 base::CheckedNumeric<int64_t> new_sum = CumulativeByteCountRead(sum); | |
| 351 new_sum += addend; | |
| 352 int64_t new_value = new_sum.ValueOrDefault(kInt64Max); | |
| 353 // Update our value. | |
| 354 #if defined(ARCH_CPU_64_BITS) | |
| 355 base::subtle::NoBarrier_Store(sum, new_value); | |
| 356 #else | |
| 357 base::subtle::NoBarrier_Store(&sum->hi_word, | |
| 358 static_cast<int32_t>(new_value >> 32)); | |
| 359 base::subtle::NoBarrier_Store(&sum->lo_word, | |
| 360 static_cast<int32_t>(new_value & 0xFFFFFFFF)); | |
| 361 #endif | |
| 262 } | 362 } |
| 263 | 363 |
| 264 //------------------------------------------------------------------------------ | 364 //------------------------------------------------------------------------------ |
| 265 DeathDataSnapshot::DeathDataSnapshot() | 365 DeathDataSnapshot::DeathDataSnapshot() |
| 266 : count(-1), | 366 : count(-1), |
| 267 run_duration_sum(-1), | 367 run_duration_sum(-1), |
| 268 run_duration_max(-1), | 368 run_duration_max(-1), |
| 269 run_duration_sample(-1), | 369 run_duration_sample(-1), |
| 270 queue_duration_sum(-1), | 370 queue_duration_sum(-1), |
| 271 queue_duration_max(-1), | 371 queue_duration_max(-1), |
| 272 queue_duration_sample(-1), | 372 queue_duration_sample(-1), |
| 273 alloc_ops(-1), | 373 alloc_ops(-1), |
| 274 free_ops(-1), | 374 free_ops(-1), |
| 275 allocated_bytes(-1), | 375 allocated_bytes(-1), |
| 276 freed_bytes(-1), | 376 freed_bytes(-1), |
| 277 alloc_overhead_bytes(-1), | 377 alloc_overhead_bytes(-1), |
| 278 max_allocated_bytes(-1) {} | 378 max_allocated_bytes(-1) {} |
| 279 | 379 |
| 280 DeathDataSnapshot::DeathDataSnapshot(int count, | 380 DeathDataSnapshot::DeathDataSnapshot(int count, |
| 281 int32_t run_duration_sum, | 381 int32_t run_duration_sum, |
| 282 int32_t run_duration_max, | 382 int32_t run_duration_max, |
| 283 int32_t run_duration_sample, | 383 int32_t run_duration_sample, |
| 284 int32_t queue_duration_sum, | 384 int32_t queue_duration_sum, |
| 285 int32_t queue_duration_max, | 385 int32_t queue_duration_max, |
| 286 int32_t queue_duration_sample, | 386 int32_t queue_duration_sample, |
| 287 int32_t alloc_ops, | 387 int32_t alloc_ops, |
| 288 int32_t free_ops, | 388 int32_t free_ops, |
| 289 int32_t allocated_bytes, | 389 int64_t allocated_bytes, |
| 290 int32_t freed_bytes, | 390 int64_t freed_bytes, |
| 291 int32_t alloc_overhead_bytes, | 391 int64_t alloc_overhead_bytes, |
| 292 int32_t max_allocated_bytes) | 392 int32_t max_allocated_bytes) |
| 293 : count(count), | 393 : count(count), |
| 294 run_duration_sum(run_duration_sum), | 394 run_duration_sum(run_duration_sum), |
| 295 run_duration_max(run_duration_max), | 395 run_duration_max(run_duration_max), |
| 296 run_duration_sample(run_duration_sample), | 396 run_duration_sample(run_duration_sample), |
| 297 queue_duration_sum(queue_duration_sum), | 397 queue_duration_sum(queue_duration_sum), |
| 298 queue_duration_max(queue_duration_max), | 398 queue_duration_max(queue_duration_max), |
| 299 queue_duration_sample(queue_duration_sample), | 399 queue_duration_sample(queue_duration_sample), |
| 300 alloc_ops(alloc_ops), | 400 alloc_ops(alloc_ops), |
| 301 free_ops(free_ops), | 401 free_ops(free_ops), |
| (...skipping 774 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1076 #endif | 1176 #endif |
| 1077 } | 1177 } |
| 1078 | 1178 |
| 1079 ProcessDataSnapshot::ProcessDataSnapshot(const ProcessDataSnapshot& other) = | 1179 ProcessDataSnapshot::ProcessDataSnapshot(const ProcessDataSnapshot& other) = |
| 1080 default; | 1180 default; |
| 1081 | 1181 |
| 1082 ProcessDataSnapshot::~ProcessDataSnapshot() { | 1182 ProcessDataSnapshot::~ProcessDataSnapshot() { |
| 1083 } | 1183 } |
| 1084 | 1184 |
| 1085 } // namespace tracked_objects | 1185 } // namespace tracked_objects |
| OLD | NEW |