|  | // Copyright 2016 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef BASE_METRICS_HISTOGRAM_PERSISTENCE_H_ | 
|  | #define BASE_METRICS_HISTOGRAM_PERSISTENCE_H_ | 
|  |  | 
|  | #include <map> | 
|  | #include <memory> | 
|  |  | 
|  | #include "base/atomicops.h" | 
|  | #include "base/base_export.h" | 
|  | #include "base/feature_list.h" | 
|  | #include "base/memory/shared_memory.h" | 
|  | #include "base/metrics/histogram_base.h" | 
|  | #include "base/metrics/persistent_memory_allocator.h" | 
|  | #include "base/process/process_handle.h" | 
|  | #include "base/strings/string_piece.h" | 
|  | #include "base/synchronization/lock.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | class BucketRanges; | 
|  | class FilePath; | 
|  | class PersistentSampleMapRecords; | 
|  | class PersistentSparseHistogramDataManager; | 
|  |  | 
|  | // Feature definition for enabling histogram persistence. | 
|  | BASE_EXPORT extern const Feature kPersistentHistogramsFeature; | 
|  |  | 
|  |  | 
|  | // A data manager for sparse histograms so each instance of such doesn't have | 
|  | // to separately iterate over the entire memory segment. Though this class | 
|  | // will generally be accessed through the PersistentHistogramAllocator above, | 
|  | // it can be used independently on any PersistentMemoryAllocator (making it | 
|  | // useable for testing). This object supports only one instance of a sparse | 
|  | // histogram for a given id. Tests that create multiple identical histograms, | 
|  | // perhaps to simulate multiple processes, should create a separate manager | 
|  | // for each. | 
|  | class BASE_EXPORT PersistentSparseHistogramDataManager { | 
|  | public: | 
|  | // Constructs the data manager. The allocator must live longer than any | 
|  | // managers that reference it. | 
|  | explicit PersistentSparseHistogramDataManager( | 
|  | PersistentMemoryAllocator* allocator); | 
|  |  | 
|  | ~PersistentSparseHistogramDataManager(); | 
|  |  | 
|  | // Returns the object that manages the persistent-sample-map records for a | 
|  | // given |id|. Only one |user| of this data is allowed at a time. This does | 
|  | // an automatic Acquire() on the records. The user must call Release() on | 
|  | // the returned object when it is finished with it. Ownership of the records | 
|  | // object stays with this manager. | 
|  | PersistentSampleMapRecords* UseSampleMapRecords(uint64_t id, | 
|  | const void* user); | 
|  |  | 
|  | // Convenience method that gets the object for a given reference so callers | 
|  | // don't have to also keep their own pointer to the appropriate allocator. | 
|  | template <typename T> | 
|  | T* GetAsObject(PersistentMemoryAllocator::Reference ref) { | 
|  | return allocator_->GetAsObject<T>(ref); | 
|  | } | 
|  |  | 
|  | private: | 
|  | friend class PersistentSampleMapRecords; | 
|  |  | 
|  | // Gets the object holding records for a given sample-map id when |lock_| | 
|  | // has already been acquired. | 
|  | PersistentSampleMapRecords* GetSampleMapRecordsWhileLocked(uint64_t id); | 
|  |  | 
|  | // Loads sample-map records looking for those belonging to the specified | 
|  | // |load_id|. Records found for other sample-maps are held for later use | 
|  | // without having to iterate again. This should be called only from a | 
|  | // PersistentSampleMapRecords object because those objects have a contract | 
|  | // that there are no other threads accessing the internal records_ field | 
|  | // of the object that is passed in. | 
|  | bool LoadRecords(PersistentSampleMapRecords* sample_map_records); | 
|  |  | 
|  | // Weak-pointer to the allocator used by the sparse histograms. | 
|  | PersistentMemoryAllocator* allocator_; | 
|  |  | 
|  | // Iterator within the allocator for finding sample records. | 
|  | PersistentMemoryAllocator::Iterator record_iterator_; | 
|  |  | 
|  | // Mapping of sample-map IDs to their sample records. | 
|  | std::map<uint64_t, std::unique_ptr<PersistentSampleMapRecords>> | 
|  | sample_records_; | 
|  |  | 
|  | // A lock used for synchronizing changes to sample_records_. | 
|  | base::Lock lock_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(PersistentSparseHistogramDataManager); | 
|  | }; | 
|  |  | 
|  |  | 
|  | // This class manages sample-records used by a PersistentSampleMap container | 
|  | // that underlies a persistent SparseHistogram object. It is broken out into a | 
|  | // top-level class so that it can be forward-declared in other header files | 
|  | // rather than include this entire file as would be necessary if it were | 
|  | // declared within the PersistentSparseHistogramDataManager class above. | 
|  | class BASE_EXPORT PersistentSampleMapRecords { | 
|  | public: | 
|  | // Constructs an instance of this class. The manager object must live longer | 
|  | // than all instances of this class that reference it, which is not usually | 
|  | // a problem since these objects are generally managed from within that | 
|  | // manager instance. | 
|  | PersistentSampleMapRecords(PersistentSparseHistogramDataManager* data_manager, | 
|  | uint64_t sample_map_id); | 
|  |  | 
|  | ~PersistentSampleMapRecords(); | 
|  |  | 
|  | // Resets the internal state for a new object using this data. The return | 
|  | // value is "this" as a convenience. | 
|  | PersistentSampleMapRecords* Acquire(const void* user); | 
|  |  | 
|  | // Indicates that the using object is done with this data. | 
|  | void Release(const void* user); | 
|  |  | 
|  | // Gets the next reference to a persistent sample-map record. The type and | 
|  | // layout of the data being referenced is defined entirely within the | 
|  | // PersistentSampleMap class. | 
|  | PersistentMemoryAllocator::Reference GetNext(); | 
|  |  | 
|  | // Creates a new persistent sample-map record for sample |value| and returns | 
|  | // a reference to it. | 
|  | PersistentMemoryAllocator::Reference CreateNew(HistogramBase::Sample value); | 
|  |  | 
|  | // Convenience method that gets the object for a given reference so callers | 
|  | // don't have to also keep their own pointer to the appropriate allocator. | 
|  | // This is expected to be used with the SampleRecord structure defined inside | 
|  | // the persistent_sample_map.cc file but since that isn't exported (for | 
|  | // cleanliness of the interface), a template is defined that will be | 
|  | // resolved when used inside that file. | 
|  | template <typename T> | 
|  | T* GetAsObject(PersistentMemoryAllocator::Reference ref) { | 
|  | return data_manager_->GetAsObject<T>(ref); | 
|  | } | 
|  |  | 
|  | private: | 
|  | friend PersistentSparseHistogramDataManager; | 
|  |  | 
|  | // Weak-pointer to the parent data-manager object. | 
|  | PersistentSparseHistogramDataManager* data_manager_; | 
|  |  | 
|  | // ID of PersistentSampleMap to which these records apply. | 
|  | const uint64_t sample_map_id_; | 
|  |  | 
|  | // The current user of this set of records. It is used to ensure that no | 
|  | // more than one object is using these records at a given time. | 
|  | const void* user_ = nullptr; | 
|  |  | 
|  | // This is the count of how many "records" have already been read by the | 
|  | // owning sample-map. | 
|  | size_t seen_ = 0; | 
|  |  | 
|  | // This is the set of records previously found for a sample map. Because | 
|  | // there is ever only one object with a given ID (typically a hash of a | 
|  | // histogram name) and because the parent SparseHistogram has acquired | 
|  | // its own lock before accessing the PersistentSampleMap it controls, this | 
|  | // list can be accessed without acquiring any additional lock. | 
|  | std::vector<PersistentMemoryAllocator::Reference> records_; | 
|  |  | 
|  | // This is the set of records found during iteration through memory. It | 
|  | // is appended in bulk to "records". Access to this vector can be done | 
|  | // only while holding the parent manager's lock. | 
|  | std::vector<PersistentMemoryAllocator::Reference> found_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(PersistentSampleMapRecords); | 
|  | }; | 
|  |  | 
|  |  | 
|  | // This class manages histograms created within a PersistentMemoryAllocator. | 
|  | class BASE_EXPORT PersistentHistogramAllocator { | 
|  | public: | 
|  | // A reference to a histogram. While this is implemented as PMA::Reference, | 
|  | // it is not conceptually the same thing. Outside callers should always use | 
|  | // a Reference matching the class it is for and not mix the two. | 
|  | using Reference = PersistentMemoryAllocator::Reference; | 
|  |  | 
|  | // Iterator used for fetching persistent histograms from an allocator. | 
|  | // It is lock-free and thread-safe. | 
|  | // See PersistentMemoryAllocator::Iterator for more information. | 
|  | class BASE_EXPORT Iterator { | 
|  | public: | 
|  | // Constructs an iterator on a given |allocator|, starting at the beginning. | 
|  | // The allocator must live beyond the lifetime of the iterator. | 
|  | explicit Iterator(PersistentHistogramAllocator* allocator); | 
|  |  | 
|  | // Gets the next histogram from persistent memory; returns null if there | 
|  | // are no more histograms to be found. This may still be called again | 
|  | // later to retrieve any new histograms added in the meantime. | 
|  | std::unique_ptr<HistogramBase> GetNext() { return GetNextWithIgnore(0); } | 
|  |  | 
|  | // Gets the next histogram from persistent memory, ignoring one particular | 
|  | // reference in the process. Pass |ignore| of zero (0) to ignore nothing. | 
|  | std::unique_ptr<HistogramBase> GetNextWithIgnore(Reference ignore); | 
|  |  | 
|  | private: | 
|  | // Weak-pointer to histogram allocator being iterated over. | 
|  | PersistentHistogramAllocator* allocator_; | 
|  |  | 
|  | // The iterator used for stepping through objects in persistent memory. | 
|  | // It is lock-free and thread-safe which is why this class is also such. | 
|  | PersistentMemoryAllocator::Iterator memory_iter_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(Iterator); | 
|  | }; | 
|  |  | 
|  | // A PersistentHistogramAllocator is constructed from a PersistentMemory- | 
|  | // Allocator object of which it takes ownership. | 
|  | explicit PersistentHistogramAllocator( | 
|  | std::unique_ptr<PersistentMemoryAllocator> memory); | 
|  | virtual ~PersistentHistogramAllocator(); | 
|  |  | 
|  | // Direct access to underlying memory allocator. If the segment is shared | 
|  | // across threads or processes, reading data through these values does | 
|  | // not guarantee consistency. Use with care. Do not write. | 
|  | PersistentMemoryAllocator* memory_allocator() { | 
|  | return memory_allocator_.get(); | 
|  | } | 
|  |  | 
|  | // Implement the "metadata" API of a PersistentMemoryAllocator, forwarding | 
|  | // those requests to the real one. | 
|  | uint64_t Id() const { return memory_allocator_->Id(); } | 
|  | const char* Name() const { return memory_allocator_->Name(); } | 
|  | const void* data() const { return memory_allocator_->data(); } | 
|  | size_t length() const { return memory_allocator_->length(); } | 
|  | size_t size() const { return memory_allocator_->size(); } | 
|  | size_t used() const { return memory_allocator_->used(); } | 
|  |  | 
|  | // Recreate a Histogram from data held in persistent memory. Though this | 
|  | // object will be local to the current process, the sample data will be | 
|  | // shared with all other threads referencing it. This method takes a |ref| | 
|  | // to where the top-level histogram data may be found in this allocator. | 
|  | // This method will return null if any problem is detected with the data. | 
|  | std::unique_ptr<HistogramBase> GetHistogram(Reference ref); | 
|  |  | 
|  | // Allocate a new persistent histogram. The returned histogram will not | 
|  | // be able to be located by other allocators until it is "finalized". | 
|  | std::unique_ptr<HistogramBase> AllocateHistogram( | 
|  | HistogramType histogram_type, | 
|  | const std::string& name, | 
|  | int minimum, | 
|  | int maximum, | 
|  | const BucketRanges* bucket_ranges, | 
|  | int32_t flags, | 
|  | Reference* ref_ptr); | 
|  |  | 
|  | // Finalize the creation of the histogram, making it available to other | 
|  | // processes if |registered| (as in: added to the StatisticsRecorder) is | 
|  | // True, forgetting it otherwise. | 
|  | void FinalizeHistogram(Reference ref, bool registered); | 
|  |  | 
|  | // Merges the data in a persistent histogram with one held globally by the | 
|  | // StatisticsRecorder, updating the "logged" samples within the passed | 
|  | // object so that repeated merges are allowed. Don't call this on a "global" | 
|  | // allocator because histograms created there will already be in the SR. | 
|  | void MergeHistogramDeltaToStatisticsRecorder(HistogramBase* histogram); | 
|  |  | 
|  | // As above but merge the "final" delta. No update of "logged" samples is | 
|  | // done which means it can operate on read-only objects. It's essential, | 
|  | // however, not to call this more than once or those final samples will | 
|  | // get recorded again. | 
|  | void MergeHistogramFinalDeltaToStatisticsRecorder( | 
|  | const HistogramBase* histogram); | 
|  |  | 
|  | // Returns the object that manages the persistent-sample-map records for a | 
|  | // given |id|. Only one |user| of this data is allowed at a time. This does | 
|  | // an automatic Acquire() on the records. The user must call Release() on | 
|  | // the returned object when it is finished with it. Ownership stays with | 
|  | // this allocator. | 
|  | PersistentSampleMapRecords* UseSampleMapRecords(uint64_t id, | 
|  | const void* user); | 
|  |  | 
|  | // Create internal histograms for tracking memory use and allocation sizes | 
|  | // for allocator of |name| (which can simply be the result of Name()). This | 
|  | // is done seperately from construction for situations such as when the | 
|  | // histograms will be backed by memory provided by this very allocator. | 
|  | // | 
|  | // IMPORTANT: Callers must update tools/metrics/histograms/histograms.xml | 
|  | // with the following histograms: | 
|  | //    UMA.PersistentAllocator.name.Allocs | 
|  | //    UMA.PersistentAllocator.name.UsedPct | 
|  | void CreateTrackingHistograms(StringPiece name); | 
|  | void UpdateTrackingHistograms(); | 
|  |  | 
|  | // Clears the internal |last_created_| reference so testing can validate | 
|  | // operation without that optimization. | 
|  | void ClearLastCreatedReferenceForTesting(); | 
|  |  | 
|  | protected: | 
|  | // The structure used to hold histogram data in persistent memory. It is | 
|  | // defined and used entirely within the .cc file. | 
|  | struct PersistentHistogramData; | 
|  |  | 
|  | // Gets the reference of the last histogram created, used to avoid | 
|  | // trying to import what was just created. | 
|  | PersistentHistogramAllocator::Reference last_created() { | 
|  | return subtle::NoBarrier_Load(&last_created_); | 
|  | } | 
|  |  | 
|  | // Gets the next histogram in persistent data based on iterator while | 
|  | // ignoring a particular reference if it is found. | 
|  | std::unique_ptr<HistogramBase> GetNextHistogramWithIgnore(Iterator* iter, | 
|  | Reference ignore); | 
|  |  | 
|  | private: | 
|  | // Create a histogram based on saved (persistent) information about it. | 
|  | std::unique_ptr<HistogramBase> CreateHistogram( | 
|  | PersistentHistogramData* histogram_data_ptr); | 
|  |  | 
|  | // Gets or creates an object in the global StatisticsRecorder matching | 
|  | // the |histogram| passed. Null is returned if one was not found and | 
|  | // one could not be created. | 
|  | HistogramBase* GetOrCreateStatisticsRecorderHistogram( | 
|  | const HistogramBase* histogram); | 
|  |  | 
|  | // The memory allocator that provides the actual histogram storage. | 
|  | std::unique_ptr<PersistentMemoryAllocator> memory_allocator_; | 
|  |  | 
|  | // The data-manager used to improve performance of sparse histograms. | 
|  | PersistentSparseHistogramDataManager sparse_histogram_data_manager_; | 
|  |  | 
|  | // A reference to the last-created histogram in the allocator, used to avoid | 
|  | // trying to import what was just created. | 
|  | // TODO(bcwhite): Change this to std::atomic<PMA::Reference> when available. | 
|  | subtle::Atomic32 last_created_ = 0; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(PersistentHistogramAllocator); | 
|  | }; | 
|  |  | 
|  |  | 
|  | // A special case of the PersistentHistogramAllocator that operates on a | 
|  | // global scale, collecting histograms created through standard macros and | 
|  | // the FactoryGet() method. | 
|  | class BASE_EXPORT GlobalHistogramAllocator | 
|  | : public PersistentHistogramAllocator { | 
|  | public: | 
|  | ~GlobalHistogramAllocator() override; | 
|  |  | 
|  | // Create a global allocator using the passed-in memory |base|, |size|, and | 
|  | // other parameters. Ownership of the memory segment remains with the caller. | 
|  | static void CreateWithPersistentMemory(void* base, | 
|  | size_t size, | 
|  | size_t page_size, | 
|  | uint64_t id, | 
|  | StringPiece name); | 
|  |  | 
|  | // Create a global allocator using an internal block of memory of the | 
|  | // specified |size| taken from the heap. | 
|  | static void CreateWithLocalMemory(size_t size, uint64_t id, StringPiece name); | 
|  |  | 
|  | #if !defined(OS_NACL) && !defined(STARBOARD) | 
|  | // Create a global allocator by memory-mapping a |file|. If the file does | 
|  | // not exist, it will be created with the specified |size|. If the file does | 
|  | // exist, the allocator will use and add to its contents, ignoring the passed | 
|  | // size in favor of the existing size. Returns whether the global allocator | 
|  | // was set. | 
|  | static bool CreateWithFile(const FilePath& file_path, | 
|  | size_t size, | 
|  | uint64_t id, | 
|  | StringPiece name); | 
|  |  | 
|  | // Creates a new file at |active_path|. If it already exists, it will first be | 
|  | // moved to |base_path|. In all cases, any old file at |base_path| will be | 
|  | // removed. If |spare_path| is non-empty and exists, that will be renamed and | 
|  | // used as the active file. Otherwise, the file will be created using the | 
|  | // given size, id, and name. Returns whether the global allocator was set. | 
|  | static bool CreateWithActiveFile(const FilePath& base_path, | 
|  | const FilePath& active_path, | 
|  | const FilePath& spare_path, | 
|  | size_t size, | 
|  | uint64_t id, | 
|  | StringPiece name); | 
|  |  | 
|  | // Uses ConstructBaseActivePairFilePaths() to build a pair of file names which | 
|  | // are then used for CreateWithActiveFile(). |name| is used for both the | 
|  | // internal name for the allocator and also for the name of the file inside | 
|  | // |dir|. | 
|  | static bool CreateWithActiveFileInDir(const FilePath& dir, | 
|  | size_t size, | 
|  | uint64_t id, | 
|  | StringPiece name); | 
|  |  | 
|  | // Constructs a filename using a name. | 
|  | static FilePath ConstructFilePath(const FilePath& dir, StringPiece name); | 
|  |  | 
|  | // Like above but with timestamp and pid for use in upload directories. | 
|  | static FilePath ConstructFilePathForUploadDir(const FilePath& dir, | 
|  | StringPiece name, | 
|  | base::Time stamp, | 
|  | ProcessId pid); | 
|  |  | 
|  | // Parses a filename to extract name, timestamp, and pid. | 
|  | static bool ParseFilePath(const FilePath& path, | 
|  | std::string* out_name, | 
|  | Time* out_stamp, | 
|  | ProcessId* out_pid); | 
|  |  | 
|  | // Constructs a set of names in |dir| based on name that can be used for a | 
|  | // base + active persistent memory mapped location for CreateWithActiveFile(). | 
|  | // The spare path is a file that can be pre-created and moved to be active | 
|  | // without any startup penalty that comes from constructing the file. |name| | 
|  | // will be used as the basename of the file inside |dir|. |out_base_path|, | 
|  | // |out_active_path|, or |out_spare_path| may be null if not needed. | 
|  | static void ConstructFilePaths(const FilePath& dir, | 
|  | StringPiece name, | 
|  | FilePath* out_base_path, | 
|  | FilePath* out_active_path, | 
|  | FilePath* out_spare_path); | 
|  |  | 
|  | // As above but puts the base files in a different "upload" directory. This | 
|  | // is useful when moving all completed files into a single directory for easy | 
|  | // upload management. | 
|  | static void ConstructFilePathsForUploadDir(const FilePath& active_dir, | 
|  | const FilePath& upload_dir, | 
|  | const std::string& name, | 
|  | FilePath* out_upload_path, | 
|  | FilePath* out_active_path, | 
|  | FilePath* out_spare_path); | 
|  |  | 
|  | // Create a "spare" file that can later be made the "active" file. This | 
|  | // should be done on a background thread if possible. | 
|  | static bool CreateSpareFile(const FilePath& spare_path, size_t size); | 
|  |  | 
|  | // Same as above but uses standard names. |name| is the name of the allocator | 
|  | // and is also used to create the correct filename. | 
|  | static bool CreateSpareFileInDir(const FilePath& dir_path, | 
|  | size_t size, | 
|  | StringPiece name); | 
|  | #endif | 
|  |  | 
|  | #if !defined(STARBOARD) | 
|  | // Create a global allocator using a block of shared memory accessed | 
|  | // through the given |handle| and |size|. The allocator takes ownership | 
|  | // of the handle and closes it upon destruction, though the memory will | 
|  | // continue to live if other processes have access to it. | 
|  | static void CreateWithSharedMemoryHandle(const SharedMemoryHandle& handle, | 
|  | size_t size); | 
|  | #endif | 
|  |  | 
|  | // Sets a GlobalHistogramAllocator for globally storing histograms in | 
|  | // a space that can be persisted or shared between processes. There is only | 
|  | // ever one allocator for all such histograms created by a single process. | 
|  | // This takes ownership of the object and should be called as soon as | 
|  | // possible during startup to capture as many histograms as possible and | 
|  | // while operating single-threaded so there are no race-conditions. | 
|  | static void Set(std::unique_ptr<GlobalHistogramAllocator> allocator); | 
|  |  | 
|  | // Gets a pointer to the global histogram allocator. Returns null if none | 
|  | // exists. | 
|  | static GlobalHistogramAllocator* Get(); | 
|  |  | 
|  | // This access to the persistent allocator is only for testing; it extracts | 
|  | // the current allocator completely. This allows easy creation of histograms | 
|  | // within persistent memory segments which can then be extracted and used in | 
|  | // other ways. | 
|  | static std::unique_ptr<GlobalHistogramAllocator> ReleaseForTesting(); | 
|  |  | 
|  | // Stores a pathname to which the contents of this allocator should be saved | 
|  | // in order to persist the data for a later use. | 
|  | void SetPersistentLocation(const FilePath& location); | 
|  |  | 
|  | // Retrieves a previously set pathname to which the contents of this allocator | 
|  | // are to be saved. | 
|  | const FilePath& GetPersistentLocation() const; | 
|  |  | 
|  | // Writes the internal data to a previously set location. This is generally | 
|  | // called when a process is exiting from a section of code that may not know | 
|  | // the filesystem. The data is written in an atomic manner. The return value | 
|  | // indicates success. | 
|  | bool WriteToPersistentLocation(); | 
|  |  | 
|  | // If there is a global metrics file being updated on disk, mark it to be | 
|  | // deleted when the process exits. | 
|  | void DeletePersistentLocation(); | 
|  |  | 
|  | private: | 
|  | friend class StatisticsRecorder; | 
|  |  | 
|  | // Creates a new global histogram allocator. | 
|  | explicit GlobalHistogramAllocator( | 
|  | std::unique_ptr<PersistentMemoryAllocator> memory); | 
|  |  | 
|  | // Import new histograms from the global histogram allocator. It's possible | 
|  | // for other processes to create histograms in the active memory segment; | 
|  | // this adds those to the internal list of known histograms to avoid creating | 
|  | // duplicates that would have to be merged during reporting. Every call to | 
|  | // this method resumes from the last entry it saw; it costs nothing if | 
|  | // nothing new has been added. | 
|  | void ImportHistogramsToStatisticsRecorder(); | 
|  |  | 
|  | // Builds a FilePath for a metrics file. | 
|  | static FilePath MakeMetricsFilePath(const FilePath& dir, StringPiece name); | 
|  |  | 
|  | // Import always continues from where it left off, making use of a single | 
|  | // iterator to continue the work. | 
|  | Iterator import_iterator_; | 
|  |  | 
|  | // The location to which the data should be persisted. | 
|  | FilePath persistent_location_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(GlobalHistogramAllocator); | 
|  | }; | 
|  |  | 
|  | }  // namespace base | 
|  |  | 
|  | #endif  // BASE_METRICS_HISTOGRAM_PERSISTENCE_H_ |