persistent_histogram_allocator.h 23 KB

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