• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #ifndef BASE_METRICS_HISTOGRAM_PERSISTENCE_H_
6 #define BASE_METRICS_HISTOGRAM_PERSISTENCE_H_
7 
8 #include <map>
9 #include <memory>
10 
11 #include "base/atomicops.h"
12 #include "base/base_export.h"
13 #include "base/feature_list.h"
14 #include "base/memory/shared_memory.h"
15 #include "base/metrics/histogram_base.h"
16 #include "base/metrics/persistent_memory_allocator.h"
17 #include "base/strings/string_piece.h"
18 #include "base/synchronization/lock.h"
19 
20 namespace base {
21 
22 class FilePath;
23 class PersistentSampleMapRecords;
24 class PersistentSparseHistogramDataManager;
25 
26 // Feature definition for enabling histogram persistence.
27 BASE_EXPORT extern const Feature kPersistentHistogramsFeature;
28 
29 
30 // A data manager for sparse histograms so each instance of such doesn't have
31 // to separately iterate over the entire memory segment. Though this class
32 // will generally be accessed through the PersistentHistogramAllocator above,
33 // it can be used independently on any PersistentMemoryAllocator (making it
34 // useable for testing). This object supports only one instance of a sparse
35 // histogram for a given id. Tests that create multiple identical histograms,
36 // perhaps to simulate multiple processes, should create a separate manager
37 // for each.
38 class BASE_EXPORT PersistentSparseHistogramDataManager {
39  public:
40   // Constructs the data manager. The allocator must live longer than any
41   // managers that reference it.
42   explicit PersistentSparseHistogramDataManager(
43       PersistentMemoryAllocator* allocator);
44 
45   ~PersistentSparseHistogramDataManager();
46 
47   // Returns the object that manages the persistent-sample-map records for a
48   // given |id|. Only one |user| of this data is allowed at a time. This does
49   // an automatic Acquire() on the records. The user must call Release() on
50   // the returned object when it is finished with it. Ownership of the records
51   // object stays with this manager.
52   PersistentSampleMapRecords* UseSampleMapRecords(uint64_t id,
53                                                   const void* user);
54 
55   // Convenience method that gets the object for a given reference so callers
56   // don't have to also keep their own pointer to the appropriate allocator.
57   template <typename T>
GetAsObject(PersistentMemoryAllocator::Reference ref,uint32_t type_id)58   T* GetAsObject(PersistentMemoryAllocator::Reference ref, uint32_t type_id) {
59     return allocator_->GetAsObject<T>(ref, type_id);
60   }
61 
62  private:
63   friend class PersistentSampleMapRecords;
64 
65   // Gets the object holding records for a given sample-map id when |lock_|
66   // has already been acquired.
67   PersistentSampleMapRecords* GetSampleMapRecordsWhileLocked(uint64_t id);
68 
69   // Loads sample-map records looking for those belonging to the specified
70   // |load_id|. Records found for other sample-maps are held for later use
71   // without having to iterate again. This should be called only from a
72   // PersistentSampleMapRecords object because those objects have a contract
73   // that there are no other threads accessing the internal records_ field
74   // of the object that is passed in.
75   bool LoadRecords(PersistentSampleMapRecords* sample_map_records);
76 
77   // Weak-pointer to the allocator used by the sparse histograms.
78   PersistentMemoryAllocator* allocator_;
79 
80   // Iterator within the allocator for finding sample records.
81   PersistentMemoryAllocator::Iterator record_iterator_;
82 
83   // Mapping of sample-map IDs to their sample records.
84   std::map<uint64_t, std::unique_ptr<PersistentSampleMapRecords>>
85       sample_records_;
86 
87   // A lock used for synchronizing changes to sample_records_.
88   base::Lock lock_;
89 
90   DISALLOW_COPY_AND_ASSIGN(PersistentSparseHistogramDataManager);
91 };
92 
93 
94 // This class manages sample-records used by a PersistentSampleMap container
95 // that underlies a persistent SparseHistogram object. It is broken out into a
96 // top-level class so that it can be forward-declared in other header files
97 // rather than include this entire file as would be necessary if it were
98 // declared within the PersistentSparseHistogramDataManager class above.
99 class BASE_EXPORT PersistentSampleMapRecords {
100  public:
101   // Constructs an instance of this class. The manager object must live longer
102   // than all instances of this class that reference it, which is not usually
103   // a problem since these objects are generally managed from within that
104   // manager instance.
105   PersistentSampleMapRecords(PersistentSparseHistogramDataManager* data_manager,
106                              uint64_t sample_map_id);
107 
108   ~PersistentSampleMapRecords();
109 
110   // Resets the internal state for a new object using this data. The return
111   // value is "this" as a convenience.
112   PersistentSampleMapRecords* Acquire(const void* user);
113 
114   // Indicates that the using object is done with this data.
115   void Release(const void* user);
116 
117   // Gets the next reference to a persistent sample-map record. The type and
118   // layout of the data being referenced is defined entirely within the
119   // PersistentSampleMap class.
120   PersistentMemoryAllocator::Reference GetNext();
121 
122   // Creates a new persistent sample-map record for sample |value| and returns
123   // a reference to it.
124   PersistentMemoryAllocator::Reference CreateNew(HistogramBase::Sample value);
125 
126   // Convenience method that gets the object for a given reference so callers
127   // don't have to also keep their own pointer to the appropriate allocator.
128   // This is expected to be used with the SampleRecord structure defined inside
129   // the persistent_sample_map.cc file but since that isn't exported (for
130   // cleanliness of the interface), a template is defined that will be
131   // resolved when used inside that file.
132   template <typename T>
GetAsObject(PersistentMemoryAllocator::Reference ref,uint32_t type_id)133   T* GetAsObject(PersistentMemoryAllocator::Reference ref, uint32_t type_id) {
134     return data_manager_->GetAsObject<T>(ref, type_id);
135   }
136 
137  private:
138   friend PersistentSparseHistogramDataManager;
139 
140   // Weak-pointer to the parent data-manager object.
141   PersistentSparseHistogramDataManager* data_manager_;
142 
143   // ID of PersistentSampleMap to which these records apply.
144   const uint64_t sample_map_id_;
145 
146   // The current user of this set of records. It is used to ensure that no
147   // more than one object is using these records at a given time.
148   const void* user_ = nullptr;
149 
150   // This is the count of how many "records" have already been read by the
151   // owning sample-map.
152   size_t seen_ = 0;
153 
154   // This is the set of records previously found for a sample map. Because
155   // there is ever only one object with a given ID (typically a hash of a
156   // histogram name) and because the parent SparseHistogram has acquired
157   // its own lock before accessing the PersistentSampleMap it controls, this
158   // list can be accessed without acquiring any additional lock.
159   std::vector<PersistentMemoryAllocator::Reference> records_;
160 
161   // This is the set of records found during iteration through memory. It
162   // is appended in bulk to "records". Access to this vector can be done
163   // only while holding the parent manager's lock.
164   std::vector<PersistentMemoryAllocator::Reference> found_;
165 
166   DISALLOW_COPY_AND_ASSIGN(PersistentSampleMapRecords);
167 };
168 
169 
170 // This class manages histograms created within a PersistentMemoryAllocator.
171 class BASE_EXPORT PersistentHistogramAllocator {
172  public:
173   // A reference to a histogram. While this is implemented as PMA::Reference,
174   // it is not conceptually the same thing. Outside callers should always use
175   // a Reference matching the class it is for and not mix the two.
176   using Reference = PersistentMemoryAllocator::Reference;
177 
178   // Iterator used for fetching persistent histograms from an allocator.
179   // It is lock-free and thread-safe.
180   // See PersistentMemoryAllocator::Iterator for more information.
181   class BASE_EXPORT Iterator {
182    public:
183     // Constructs an iterator on a given |allocator|, starting at the beginning.
184     // The allocator must live beyond the lifetime of the iterator.
185     explicit Iterator(PersistentHistogramAllocator* allocator);
186 
187     // Gets the next histogram from persistent memory; returns null if there
188     // are no more histograms to be found. This may still be called again
189     // later to retrieve any new histograms added in the meantime.
GetNext()190     std::unique_ptr<HistogramBase> GetNext() { return GetNextWithIgnore(0); }
191 
192     // Gets the next histogram from persistent memory, ignoring one particular
193     // reference in the process. Pass |ignore| of zero (0) to ignore nothing.
194     std::unique_ptr<HistogramBase> GetNextWithIgnore(Reference ignore);
195 
196    private:
197     // Weak-pointer to histogram allocator being iterated over.
198     PersistentHistogramAllocator* allocator_;
199 
200     // The iterator used for stepping through objects in persistent memory.
201     // It is lock-free and thread-safe which is why this class is also such.
202     PersistentMemoryAllocator::Iterator memory_iter_;
203 
204     DISALLOW_COPY_AND_ASSIGN(Iterator);
205   };
206 
207   // A PersistentHistogramAllocator is constructed from a PersistentMemory-
208   // Allocator object of which it takes ownership.
209   explicit PersistentHistogramAllocator(
210       std::unique_ptr<PersistentMemoryAllocator> memory);
211   virtual ~PersistentHistogramAllocator();
212 
213   // Direct access to underlying memory allocator. If the segment is shared
214   // across threads or processes, reading data through these values does
215   // not guarantee consistency. Use with care. Do not write.
memory_allocator()216   PersistentMemoryAllocator* memory_allocator() {
217     return memory_allocator_.get();
218   }
219 
220   // Implement the "metadata" API of a PersistentMemoryAllocator, forwarding
221   // those requests to the real one.
Id()222   uint64_t Id() const { return memory_allocator_->Id(); }
Name()223   const char* Name() const { return memory_allocator_->Name(); }
data()224   const void* data() const { return memory_allocator_->data(); }
length()225   size_t length() const { return memory_allocator_->length(); }
size()226   size_t size() const { return memory_allocator_->size(); }
used()227   size_t used() const { return memory_allocator_->used(); }
228 
229   // Recreate a Histogram from data held in persistent memory. Though this
230   // object will be local to the current process, the sample data will be
231   // shared with all other threads referencing it. This method takes a |ref|
232   // to where the top-level histogram data may be found in this allocator.
233   // This method will return null if any problem is detected with the data.
234   std::unique_ptr<HistogramBase> GetHistogram(Reference ref);
235 
236   // Allocate a new persistent histogram. The returned histogram will not
237   // be able to be located by other allocators until it is "finalized".
238   std::unique_ptr<HistogramBase> AllocateHistogram(
239       HistogramType histogram_type,
240       const std::string& name,
241       int minimum,
242       int maximum,
243       const BucketRanges* bucket_ranges,
244       int32_t flags,
245       Reference* ref_ptr);
246 
247   // Finalize the creation of the histogram, making it available to other
248   // processes if |registered| (as in: added to the StatisticsRecorder) is
249   // True, forgetting it otherwise.
250   void FinalizeHistogram(Reference ref, bool registered);
251 
252   // Merges the data in a persistent histogram with one held globally by the
253   // StatisticsRecorder, updating the "logged" samples within the passed
254   // object so that repeated merges are allowed. Don't call this on a "global"
255   // allocator because histograms created there will already be in the SR.
256   void MergeHistogramDeltaToStatisticsRecorder(HistogramBase* histogram);
257 
258   // As above but merge the "final" delta. No update of "logged" samples is
259   // done which means it can operate on read-only objects. It's essential,
260   // however, not to call this more than once or those final samples will
261   // get recorded again.
262   void MergeHistogramFinalDeltaToStatisticsRecorder(
263       const HistogramBase* histogram);
264 
265   // Returns the object that manages the persistent-sample-map records for a
266   // given |id|. Only one |user| of this data is allowed at a time. This does
267   // an automatic Acquire() on the records. The user must call Release() on
268   // the returned object when it is finished with it. Ownership stays with
269   // this allocator.
270   PersistentSampleMapRecords* UseSampleMapRecords(uint64_t id,
271                                                   const void* user);
272 
273   // Create internal histograms for tracking memory use and allocation sizes
274   // for allocator of |name| (which can simply be the result of Name()). This
275   // is done seperately from construction for situations such as when the
276   // histograms will be backed by memory provided by this very allocator.
277   //
278   // IMPORTANT: Callers must update tools/metrics/histograms/histograms.xml
279   // with the following histograms:
280   //    UMA.PersistentAllocator.name.Allocs
281   //    UMA.PersistentAllocator.name.UsedPct
282   void CreateTrackingHistograms(StringPiece name);
283   void UpdateTrackingHistograms();
284 
285   // Clears the internal |last_created_| reference so testing can validate
286   // operation without that optimization.
287   void ClearLastCreatedReferenceForTesting();
288 
289   // Histogram containing creation results. Visible for testing.
290   static HistogramBase* GetCreateHistogramResultHistogram();
291 
292  protected:
293   // The structure used to hold histogram data in persistent memory. It is
294   // defined and used entirely within the .cc file.
295   struct PersistentHistogramData;
296 
297   // Gets the reference of the last histogram created, used to avoid
298   // trying to import what was just created.
last_created()299   PersistentHistogramAllocator::Reference last_created() {
300     return subtle::NoBarrier_Load(&last_created_);
301   }
302 
303   // Gets the next histogram in persistent data based on iterator while
304   // ignoring a particular reference if it is found.
305   std::unique_ptr<HistogramBase> GetNextHistogramWithIgnore(Iterator* iter,
306                                                             Reference ignore);
307 
308  private:
309   // Enumerate possible creation results for reporting.
310   enum CreateHistogramResultType {
311     // Everything was fine.
312     CREATE_HISTOGRAM_SUCCESS = 0,
313 
314     // Pointer to metadata was not valid.
315     CREATE_HISTOGRAM_INVALID_METADATA_POINTER,
316 
317     // Histogram metadata was not valid.
318     CREATE_HISTOGRAM_INVALID_METADATA,
319 
320     // Ranges information was not valid.
321     CREATE_HISTOGRAM_INVALID_RANGES_ARRAY,
322 
323     // Counts information was not valid.
324     CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY,
325 
326     // Could not allocate histogram memory due to corruption.
327     CREATE_HISTOGRAM_ALLOCATOR_CORRUPT,
328 
329     // Could not allocate histogram memory due to lack of space.
330     CREATE_HISTOGRAM_ALLOCATOR_FULL,
331 
332     // Could not allocate histogram memory due to unknown error.
333     CREATE_HISTOGRAM_ALLOCATOR_ERROR,
334 
335     // Histogram was of unknown type.
336     CREATE_HISTOGRAM_UNKNOWN_TYPE,
337 
338     // Instance has detected a corrupt allocator (recorded only once).
339     CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT,
340 
341     // Always keep this at the end.
342     CREATE_HISTOGRAM_MAX
343   };
344 
345   // Create a histogram based on saved (persistent) information about it.
346   std::unique_ptr<HistogramBase> CreateHistogram(
347       PersistentHistogramData* histogram_data_ptr);
348 
349   // Gets or creates an object in the global StatisticsRecorder matching
350   // the |histogram| passed. Null is returned if one was not found and
351   // one could not be created.
352   HistogramBase* GetOrCreateStatisticsRecorderHistogram(
353       const HistogramBase* histogram);
354 
355   // Record the result of a histogram creation.
356   static void RecordCreateHistogramResult(CreateHistogramResultType result);
357 
358   // The memory allocator that provides the actual histogram storage.
359   std::unique_ptr<PersistentMemoryAllocator> memory_allocator_;
360 
361   // The data-manager used to improve performance of sparse histograms.
362   PersistentSparseHistogramDataManager sparse_histogram_data_manager_;
363 
364   // A reference to the last-created histogram in the allocator, used to avoid
365   // trying to import what was just created.
366   // TODO(bcwhite): Change this to std::atomic<PMA::Reference> when available.
367   subtle::Atomic32 last_created_ = 0;
368 
369   DISALLOW_COPY_AND_ASSIGN(PersistentHistogramAllocator);
370 };
371 
372 
373 // A special case of the PersistentHistogramAllocator that operates on a
374 // global scale, collecting histograms created through standard macros and
375 // the FactoryGet() method.
376 class BASE_EXPORT GlobalHistogramAllocator
377     : public PersistentHistogramAllocator {
378  public:
379   ~GlobalHistogramAllocator() override;
380 
381   // Create a global allocator using the passed-in memory |base|, |size|, and
382   // other parameters. Ownership of the memory segment remains with the caller.
383   static void CreateWithPersistentMemory(void* base,
384                                          size_t size,
385                                          size_t page_size,
386                                          uint64_t id,
387                                          StringPiece name);
388 
389   // Create a global allocator using an internal block of memory of the
390   // specified |size| taken from the heap.
391   static void CreateWithLocalMemory(size_t size, uint64_t id, StringPiece name);
392 
393 #if !defined(OS_NACL)
394   // Create a global allocator by memory-mapping a |file|. If the file does
395   // not exist, it will be created with the specified |size|. If the file does
396   // exist, the allocator will use and add to its contents, ignoring the passed
397   // size in favor of the existing size.
398   static void CreateWithFile(const FilePath& file_path,
399                              size_t size,
400                              uint64_t id,
401                              StringPiece name);
402 #endif
403 
404   // Create a global allocator using a block of shared |memory| of the
405   // specified |size|. The allocator takes ownership of the shared memory
406   // and releases it upon destruction, though the memory will continue to
407   // live if other processes have access to it.
408   static void CreateWithSharedMemory(std::unique_ptr<SharedMemory> memory,
409                                      size_t size,
410                                      uint64_t id,
411                                      StringPiece name);
412 
413   // Create a global allocator using a block of shared memory accessed
414   // through the given |handle| and |size|. The allocator takes ownership
415   // of the handle and closes it upon destruction, though the memory will
416   // continue to live if other processes have access to it.
417   static void CreateWithSharedMemoryHandle(const SharedMemoryHandle& handle,
418                                            size_t size);
419 
420   // Sets a GlobalHistogramAllocator for globally storing histograms in
421   // a space that can be persisted or shared between processes. There is only
422   // ever one allocator for all such histograms created by a single process.
423   // This takes ownership of the object and should be called as soon as
424   // possible during startup to capture as many histograms as possible and
425   // while operating single-threaded so there are no race-conditions.
426   static void Set(std::unique_ptr<GlobalHistogramAllocator> allocator);
427 
428   // Gets a pointer to the global histogram allocator. Returns null if none
429   // exists.
430   static GlobalHistogramAllocator* Get();
431 
432   // This access to the persistent allocator is only for testing; it extracts
433   // the current allocator completely. This allows easy creation of histograms
434   // within persistent memory segments which can then be extracted and used in
435   // other ways.
436   static std::unique_ptr<GlobalHistogramAllocator> ReleaseForTesting();
437 
438   // Stores a pathname to which the contents of this allocator should be saved
439   // in order to persist the data for a later use.
440   void SetPersistentLocation(const FilePath& location);
441 
442   // Retrieves a previously set pathname to which the contents of this allocator
443   // are to be saved.
444   const FilePath& GetPersistentLocation() const;
445 
446   // Writes the internal data to a previously set location. This is generally
447   // called when a process is exiting from a section of code that may not know
448   // the filesystem. The data is written in an atomic manner. The return value
449   // indicates success.
450   bool WriteToPersistentLocation();
451 
452  private:
453   friend class StatisticsRecorder;
454 
455   // Creates a new global histogram allocator.
456   explicit GlobalHistogramAllocator(
457       std::unique_ptr<PersistentMemoryAllocator> memory);
458 
459   // Import new histograms from the global histogram allocator. It's possible
460   // for other processes to create histograms in the active memory segment;
461   // this adds those to the internal list of known histograms to avoid creating
462   // duplicates that would have to be merged during reporting. Every call to
463   // this method resumes from the last entry it saw; it costs nothing if
464   // nothing new has been added.
465   void ImportHistogramsToStatisticsRecorder();
466 
467   // Import always continues from where it left off, making use of a single
468   // iterator to continue the work.
469   Iterator import_iterator_;
470 
471   // The location to which the data should be persisted.
472   FilePath persistent_location_;
473 
474   DISALLOW_COPY_AND_ASSIGN(GlobalHistogramAllocator);
475 };
476 
477 }  // namespace base
478 
479 #endif  // BASE_METRICS_HISTOGRAM_PERSISTENCE_H_
480