| 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_sample_map.h" | 5 #include "base/metrics/persistent_sample_map.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
| 9 #include "base/metrics/histogram_macros.h" | 9 #include "base/metrics/histogram_macros.h" |
| 10 #include "base/metrics/persistent_histogram_allocator.h" | 10 #include "base/metrics/persistent_histogram_allocator.h" |
| 11 #include "base/numerics/safe_conversions.h" | 11 #include "base/numerics/safe_conversions.h" |
| 12 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
| 13 | 13 |
| 14 namespace base { | 14 namespace base { |
| 15 | 15 |
| 16 typedef HistogramBase::Count Count; | 16 typedef HistogramBase::Count Count; |
| 17 typedef HistogramBase::Sample Sample; | 17 typedef HistogramBase::Sample Sample; |
| 18 | 18 |
| 19 namespace { | 19 namespace { |
| 20 | 20 |
| 21 enum NegativeSampleReason { | 21 enum NegativeSampleReason { |
| 22 PERSISTENT_SPARSE_HAVE_LOGGED_BUT_NOT_SAMPLE, | 22 PERSISTENT_SPARSE_HAVE_LOGGED_BUT_NOT_SAMPLE, |
| 23 PERSISTENT_SPARSE_SAMPLE_LESS_THAN_LOGGED, | 23 PERSISTENT_SPARSE_SAMPLE_LESS_THAN_LOGGED, |
| 24 PERSISTENT_SPARSE_ADDED_NEGATIVE_COUNT, | 24 PERSISTENT_SPARSE_ADDED_NEGATIVE_COUNT, |
| 25 PERSISTENT_SPARSE_ADD_WENT_NEGATIVE, | 25 PERSISTENT_SPARSE_ADD_WENT_NEGATIVE, |
| 26 PERSISTENT_SPARSE_ADD_OVERFLOW, | 26 PERSISTENT_SPARSE_ADD_OVERFLOW, |
| 27 PERSISTENT_SPARSE_ACCUMULATE_NEGATIVE_COUNT, |
| 28 PERSISTENT_SPARSE_ACCUMULATE_WENT_NEGATIVE, |
| 29 PERSISTENT_SPARSE_ACCUMULATE_OVERFLOW, |
| 27 MAX_NEGATIVE_SAMPLE_REASONS | 30 MAX_NEGATIVE_SAMPLE_REASONS |
| 28 }; | 31 }; |
| 29 | 32 |
| 30 // An iterator for going through a PersistentSampleMap. The logic here is | 33 // An iterator for going through a PersistentSampleMap. The logic here is |
| 31 // identical to that of SampleMapIterator but with different data structures. | 34 // identical to that of SampleMapIterator but with different data structures. |
| 32 // Changes here likely need to be duplicated there. | 35 // Changes here likely need to be duplicated there. |
| 33 class PersistentSampleMapIterator : public SampleCountIterator { | 36 class PersistentSampleMapIterator : public SampleCountIterator { |
| 34 public: | 37 public: |
| 35 typedef std::map<HistogramBase::Sample, HistogramBase::Count*> | 38 typedef std::map<HistogramBase::Sample, HistogramBase::Count*> |
| 36 SampleToCountMap; | 39 SampleToCountMap; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 PersistentHistogramAllocator* allocator, | 114 PersistentHistogramAllocator* allocator, |
| 112 Metadata* meta) | 115 Metadata* meta) |
| 113 : HistogramSamples(id, meta), allocator_(allocator) {} | 116 : HistogramSamples(id, meta), allocator_(allocator) {} |
| 114 | 117 |
| 115 PersistentSampleMap::~PersistentSampleMap() { | 118 PersistentSampleMap::~PersistentSampleMap() { |
| 116 if (records_) | 119 if (records_) |
| 117 records_->Release(this); | 120 records_->Release(this); |
| 118 } | 121 } |
| 119 | 122 |
| 120 void PersistentSampleMap::Accumulate(Sample value, Count count) { | 123 void PersistentSampleMap::Accumulate(Sample value, Count count) { |
| 124 #if 0 // TODO(bcwhite) Re-enable efficient version after crbug.com/682680. |
| 121 *GetOrCreateSampleCountStorage(value) += count; | 125 *GetOrCreateSampleCountStorage(value) += count; |
| 126 #else |
| 127 NegativeSampleReason reason = MAX_NEGATIVE_SAMPLE_REASONS; |
| 128 Count* local_count_ptr = GetOrCreateSampleCountStorage(value); |
| 129 if (count < 0) { |
| 130 reason = PERSISTENT_SPARSE_ACCUMULATE_NEGATIVE_COUNT; |
| 131 if (*local_count_ptr < -count) |
| 132 reason = PERSISTENT_SPARSE_ACCUMULATE_WENT_NEGATIVE; |
| 133 *local_count_ptr += count; |
| 134 } else { |
| 135 *local_count_ptr += count; |
| 136 if (*local_count_ptr < 0) |
| 137 reason = PERSISTENT_SPARSE_ACCUMULATE_OVERFLOW; |
| 138 } |
| 139 if (reason != MAX_NEGATIVE_SAMPLE_REASONS) { |
| 140 UMA_HISTOGRAM_ENUMERATION("UMA.NegativeSamples.Reason", reason, |
| 141 MAX_NEGATIVE_SAMPLE_REASONS); |
| 142 } |
| 143 #endif |
| 122 IncreaseSumAndCount(strict_cast<int64_t>(count) * value, count); | 144 IncreaseSumAndCount(strict_cast<int64_t>(count) * value, count); |
| 123 } | 145 } |
| 124 | 146 |
| 125 Count PersistentSampleMap::GetCount(Sample value) const { | 147 Count PersistentSampleMap::GetCount(Sample value) const { |
| 126 // Have to override "const" to make sure all samples have been loaded before | 148 // Have to override "const" to make sure all samples have been loaded before |
| 127 // being able to know what value to return. | 149 // being able to know what value to return. |
| 128 Count* count_pointer = | 150 Count* count_pointer = |
| 129 const_cast<PersistentSampleMap*>(this)->GetSampleCountStorage(value); | 151 const_cast<PersistentSampleMap*>(this)->GetSampleCountStorage(value); |
| 130 return count_pointer ? *count_pointer : 0; | 152 return count_pointer ? *count_pointer : 0; |
| 131 } | 153 } |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 Operator op) { | 210 Operator op) { |
| 189 Sample min; | 211 Sample min; |
| 190 int64_t max; | 212 int64_t max; |
| 191 Count count; | 213 Count count; |
| 192 for (; !iter->Done(); iter->Next()) { | 214 for (; !iter->Done(); iter->Next()) { |
| 193 iter->Get(&min, &max, &count); | 215 iter->Get(&min, &max, &count); |
| 194 if (count == 0) | 216 if (count == 0) |
| 195 continue; | 217 continue; |
| 196 if (strict_cast<int64_t>(min) + 1 != max) | 218 if (strict_cast<int64_t>(min) + 1 != max) |
| 197 return false; // SparseHistogram only supports bucket with size 1. | 219 return false; // SparseHistogram only supports bucket with size 1. |
| 198 | |
| 199 #if 0 // TODO(bcwhite) Re-enable efficient version after crbug.com/682680. | |
| 200 *GetOrCreateSampleCountStorage(min) += | 220 *GetOrCreateSampleCountStorage(min) += |
| 201 (op == HistogramSamples::ADD) ? count : -count; | 221 (op == HistogramSamples::ADD) ? count : -count; |
| 202 #else | |
| 203 NegativeSampleReason reason = MAX_NEGATIVE_SAMPLE_REASONS; | |
| 204 if (op == HistogramSamples::ADD) { | |
| 205 // Add should generally be adding only positive values. | |
| 206 Count* local_count_ptr = GetOrCreateSampleCountStorage(min); | |
| 207 if (count < 0) { | |
| 208 reason = PERSISTENT_SPARSE_ADDED_NEGATIVE_COUNT; | |
| 209 if (*local_count_ptr < -count) { | |
| 210 reason = PERSISTENT_SPARSE_ADD_WENT_NEGATIVE; | |
| 211 *local_count_ptr = 0; | |
| 212 } | |
| 213 } else { | |
| 214 *local_count_ptr += count; | |
| 215 if (*local_count_ptr < 0) | |
| 216 reason = PERSISTENT_SPARSE_ADD_OVERFLOW; | |
| 217 } | |
| 218 } else { | |
| 219 // Subtract is used only for determining deltas when reporting which | |
| 220 // means that it's in the "logged" iterator. It should have an active | |
| 221 // sample record and thus there is no need to try to create one. | |
| 222 Count* local_count_ptr = GetSampleCountStorage(min); | |
| 223 if (local_count_ptr == nullptr) { | |
| 224 reason = PERSISTENT_SPARSE_HAVE_LOGGED_BUT_NOT_SAMPLE; | |
| 225 } else { | |
| 226 if (*local_count_ptr < count) { | |
| 227 reason = PERSISTENT_SPARSE_SAMPLE_LESS_THAN_LOGGED; | |
| 228 *local_count_ptr = 0; | |
| 229 } else { | |
| 230 *local_count_ptr -= count; | |
| 231 } | |
| 232 } | |
| 233 } | |
| 234 if (reason != MAX_NEGATIVE_SAMPLE_REASONS) { | |
| 235 NOTREACHED(); | |
| 236 UMA_HISTOGRAM_ENUMERATION("UMA.NegativeSamples.Reason", reason, | |
| 237 MAX_NEGATIVE_SAMPLE_REASONS); | |
| 238 } | |
| 239 #endif | |
| 240 } | 222 } |
| 241 return true; | 223 return true; |
| 242 } | 224 } |
| 243 | 225 |
| 244 Count* PersistentSampleMap::GetSampleCountStorage(Sample value) { | 226 Count* PersistentSampleMap::GetSampleCountStorage(Sample value) { |
| 245 // If |value| is already in the map, just return that. | 227 // If |value| is already in the map, just return that. |
| 246 auto it = sample_counts_.find(value); | 228 auto it = sample_counts_.find(value); |
| 247 if (it != sample_counts_.end()) | 229 if (it != sample_counts_.end()) |
| 248 return it->second; | 230 return it->second; |
| 249 | 231 |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 found_count = &record->count; | 310 found_count = &record->count; |
| 329 if (!import_everything) | 311 if (!import_everything) |
| 330 break; | 312 break; |
| 331 } | 313 } |
| 332 } | 314 } |
| 333 | 315 |
| 334 return found_count; | 316 return found_count; |
| 335 } | 317 } |
| 336 | 318 |
| 337 } // namespace base | 319 } // namespace base |
| OLD | NEW |