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 protected: 291 // The structure used to hold histogram data in persistent memory. It is 292 // defined and used entirely within the .cc file. 293 struct PersistentHistogramData; 294 295 // Gets the reference of the last histogram created, used to avoid 296 // trying to import what was just created. last_created()297 PersistentHistogramAllocator::Reference last_created() { 298 return subtle::NoBarrier_Load(&last_created_); 299 } 300 301 // Gets the next histogram in persistent data based on iterator while 302 // ignoring a particular reference if it is found. 303 std::unique_ptr<HistogramBase> GetNextHistogramWithIgnore(Iterator* iter, 304 Reference ignore); 305 306 private: 307 // Create a histogram based on saved (persistent) information about it. 308 std::unique_ptr<HistogramBase> CreateHistogram( 309 PersistentHistogramData* histogram_data_ptr); 310 311 // Gets or creates an object in the global StatisticsRecorder matching 312 // the |histogram| passed. Null is returned if one was not found and 313 // one could not be created. 314 HistogramBase* GetOrCreateStatisticsRecorderHistogram( 315 const HistogramBase* histogram); 316 317 // The memory allocator that provides the actual histogram storage. 318 std::unique_ptr<PersistentMemoryAllocator> memory_allocator_; 319 320 // The data-manager used to improve performance of sparse histograms. 321 PersistentSparseHistogramDataManager sparse_histogram_data_manager_; 322 323 // A reference to the last-created histogram in the allocator, used to avoid 324 // trying to import what was just created. 325 // TODO(bcwhite): Change this to std::atomic<PMA::Reference> when available. 326 subtle::Atomic32 last_created_ = 0; 327 328 DISALLOW_COPY_AND_ASSIGN(PersistentHistogramAllocator); 329 }; 330 331 332 // A special case of the PersistentHistogramAllocator that operates on a 333 // global scale, collecting histograms created through standard macros and 334 // the FactoryGet() method. 335 class BASE_EXPORT GlobalHistogramAllocator 336 : public PersistentHistogramAllocator { 337 public: 338 ~GlobalHistogramAllocator() override; 339 340 // Create a global allocator using the passed-in memory |base|, |size|, and 341 // other parameters. Ownership of the memory segment remains with the caller. 342 static void CreateWithPersistentMemory(void* base, 343 size_t size, 344 size_t page_size, 345 uint64_t id, 346 StringPiece name); 347 348 // Create a global allocator using an internal block of memory of the 349 // specified |size| taken from the heap. 350 static void CreateWithLocalMemory(size_t size, uint64_t id, StringPiece name); 351 352 #if !defined(OS_NACL) 353 // Create a global allocator by memory-mapping a |file|. If the file does 354 // not exist, it will be created with the specified |size|. If the file does 355 // exist, the allocator will use and add to its contents, ignoring the passed 356 // size in favor of the existing size. Returns whether the global allocator 357 // was set. 358 static bool CreateWithFile(const FilePath& file_path, 359 size_t size, 360 uint64_t id, 361 StringPiece name); 362 363 // Creates a new file at |active_path|. If it already exists, it will first be 364 // moved to |base_path|. In all cases, any old file at |base_path| will be 365 // removed. If |spare_path| is non-empty and exists, that will be renamed and 366 // used as the active file. Otherwise, the file will be created using the 367 // given size, id, and name. Returns whether the global allocator was set. 368 static bool CreateWithActiveFile(const FilePath& base_path, 369 const FilePath& active_path, 370 const FilePath& spare_path, 371 size_t size, 372 uint64_t id, 373 StringPiece name); 374 375 // Uses ConstructBaseActivePairFilePaths() to build a pair of file names which 376 // are then used for CreateWithActiveFile(). |name| is used for both the 377 // internal name for the allocator and also for the name of the file inside 378 // |dir|. 379 static bool CreateWithActiveFileInDir(const FilePath& dir, 380 size_t size, 381 uint64_t id, 382 StringPiece name); 383 384 // Constructs a filename using a name. 385 static FilePath ConstructFilePath(const FilePath& dir, StringPiece name); 386 387 // Like above but with timestamp and pid for use in upload directories. 388 static FilePath ConstructFilePathForUploadDir(const FilePath& dir, 389 StringPiece name, 390 base::Time stamp, 391 ProcessId pid); 392 393 // Parses a filename to extract name, timestamp, and pid. 394 static bool ParseFilePath(const FilePath& path, 395 std::string* out_name, 396 Time* out_stamp, 397 ProcessId* out_pid); 398 399 // Constructs a set of names in |dir| based on name that can be used for a 400 // base + active persistent memory mapped location for CreateWithActiveFile(). 401 // The spare path is a file that can be pre-created and moved to be active 402 // without any startup penalty that comes from constructing the file. |name| 403 // will be used as the basename of the file inside |dir|. |out_base_path|, 404 // |out_active_path|, or |out_spare_path| may be null if not needed. 405 static void ConstructFilePaths(const FilePath& dir, 406 StringPiece name, 407 FilePath* out_base_path, 408 FilePath* out_active_path, 409 FilePath* out_spare_path); 410 411 // As above but puts the base files in a different "upload" directory. This 412 // is useful when moving all completed files into a single directory for easy 413 // upload management. 414 static void ConstructFilePathsForUploadDir(const FilePath& active_dir, 415 const FilePath& upload_dir, 416 const std::string& name, 417 FilePath* out_upload_path, 418 FilePath* out_active_path, 419 FilePath* out_spare_path); 420 421 // Create a "spare" file that can later be made the "active" file. This 422 // should be done on a background thread if possible. 423 static bool CreateSpareFile(const FilePath& spare_path, size_t size); 424 425 // Same as above but uses standard names. |name| is the name of the allocator 426 // and is also used to create the correct filename. 427 static bool CreateSpareFileInDir(const FilePath& dir_path, 428 size_t size, 429 StringPiece name); 430 #endif 431 432 // Create a global allocator using a block of shared memory accessed 433 // through the given |handle| and |size|. The allocator takes ownership 434 // of the handle and closes it upon destruction, though the memory will 435 // continue to live if other processes have access to it. 436 static void CreateWithSharedMemoryHandle(const SharedMemoryHandle& handle, 437 size_t size); 438 439 // Sets a GlobalHistogramAllocator for globally storing histograms in 440 // a space that can be persisted or shared between processes. There is only 441 // ever one allocator for all such histograms created by a single process. 442 // This takes ownership of the object and should be called as soon as 443 // possible during startup to capture as many histograms as possible and 444 // while operating single-threaded so there are no race-conditions. 445 static void Set(std::unique_ptr<GlobalHistogramAllocator> allocator); 446 447 // Gets a pointer to the global histogram allocator. Returns null if none 448 // exists. 449 static GlobalHistogramAllocator* Get(); 450 451 // This access to the persistent allocator is only for testing; it extracts 452 // the current allocator completely. This allows easy creation of histograms 453 // within persistent memory segments which can then be extracted and used in 454 // other ways. 455 static std::unique_ptr<GlobalHistogramAllocator> ReleaseForTesting(); 456 457 // Stores a pathname to which the contents of this allocator should be saved 458 // in order to persist the data for a later use. 459 void SetPersistentLocation(const FilePath& location); 460 461 // Retrieves a previously set pathname to which the contents of this allocator 462 // are to be saved. 463 const FilePath& GetPersistentLocation() const; 464 465 // Writes the internal data to a previously set location. This is generally 466 // called when a process is exiting from a section of code that may not know 467 // the filesystem. The data is written in an atomic manner. The return value 468 // indicates success. 469 bool WriteToPersistentLocation(); 470 471 // If there is a global metrics file being updated on disk, mark it to be 472 // deleted when the process exits. 473 void DeletePersistentLocation(); 474 475 private: 476 friend class StatisticsRecorder; 477 478 // Creates a new global histogram allocator. 479 explicit GlobalHistogramAllocator( 480 std::unique_ptr<PersistentMemoryAllocator> memory); 481 482 // Import new histograms from the global histogram allocator. It's possible 483 // for other processes to create histograms in the active memory segment; 484 // this adds those to the internal list of known histograms to avoid creating 485 // duplicates that would have to be merged during reporting. Every call to 486 // this method resumes from the last entry it saw; it costs nothing if 487 // nothing new has been added. 488 void ImportHistogramsToStatisticsRecorder(); 489 490 // Builds a FilePath for a metrics file. 491 static FilePath MakeMetricsFilePath(const FilePath& dir, StringPiece name); 492 493 // Import always continues from where it left off, making use of a single 494 // iterator to continue the work. 495 Iterator import_iterator_; 496 497 // The location to which the data should be persisted. 498 FilePath persistent_location_; 499 500 DISALLOW_COPY_AND_ASSIGN(GlobalHistogramAllocator); 501 }; 502 503 } // namespace base 504 505 #endif // BASE_METRICS_HISTOGRAM_PERSISTENCE_H_ 506