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