|  | /* | 
|  | * Copyright 2016 Google Inc. All Rights Reserved. | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #ifndef NB_MEMORY_TRACKER_H_ | 
|  | #define NB_MEMORY_TRACKER_H_ | 
|  |  | 
|  | #include <vector> | 
|  | #include "starboard/configuration.h" | 
|  | #include "starboard/types.h" | 
|  |  | 
|  | struct NbMemoryScopeInfo; | 
|  |  | 
|  | namespace nb { | 
|  | namespace analytics { | 
|  |  | 
|  | class MemoryTracker; | 
|  | class MemoryTrackerDebugCallback; | 
|  | class AllocationVisitor; | 
|  | class AllocationGroup; | 
|  |  | 
|  | struct MemoryStats { | 
|  | MemoryStats() : total_cpu_memory(0), used_cpu_memory(0), | 
|  | total_gpu_memory(0), used_gpu_memory(0) {} | 
|  | int64_t total_cpu_memory; | 
|  | int64_t used_cpu_memory; | 
|  | int64_t total_gpu_memory; | 
|  | int64_t used_gpu_memory; | 
|  | }; | 
|  |  | 
|  | MemoryStats GetProcessMemoryStats(); | 
|  |  | 
|  | typedef std::vector<AllocationGroup*> AllocationGroupPtrVec; | 
|  | typedef std::vector<const NbMemoryScopeInfo*> CallStack; | 
|  |  | 
|  | // Contains an allocation record for a pointer including it's size and what | 
|  | // AllocationGroup it was constructed under. | 
|  | class AllocationRecord { | 
|  | public: | 
|  | AllocationRecord() : size(0), allocation_group(NULL) {} | 
|  | AllocationRecord(size_t sz, AllocationGroup* group) | 
|  | : size(sz), allocation_group(group) {} | 
|  |  | 
|  | static AllocationRecord Empty() { return AllocationRecord(); } | 
|  | bool IsEmpty() const { return !size && !allocation_group; } | 
|  | size_t size; | 
|  | AllocationGroup* allocation_group; | 
|  | }; | 
|  |  | 
|  | // Creates a MemoryTracker instance that implements the | 
|  | //  MemoryTracker. Once the instance is created it can begin tracking | 
|  | //  system allocations by calling InstallGlobalTrackingHooks(). | 
|  | //  Deleting the MemoryTracker is forbidden. | 
|  | // | 
|  | // Example, Creation and Hooking: | 
|  | //   static MemoryTracker* s_global_tracker = | 
|  | //       GetOrCreateMemoryTracker(); | 
|  | //   s_global_tracker->InstallGlobalTrackingHooks();  // now tracking memory. | 
|  | // | 
|  | // Data about the allocations are aggregated under AllocationGroups and it's | 
|  | //  recommended that GetAllocationGroups(...) is used to get simple allocation | 
|  | //  statistics. | 
|  | // | 
|  | // Deeper analytics are possible by creating an AllocationVisitor subclass and | 
|  | //  traversing through the internal allocations of the tracker. In this way all | 
|  | //  known information about allocation state of the program is made accessible. | 
|  | //  The visitor does not need to perform any locking as this is guaranteed by | 
|  | //  the MemoryTracker. | 
|  | // | 
|  | // Example (AllocationVisitor): | 
|  | //  MyAllocation visitor = ...; | 
|  | //  s_global_tracker->Accept(&visitor); | 
|  | //  visitor.PrintAllocations(); | 
|  | // | 
|  | // Performance: | 
|  | //  1) Gold builds disallow memory tracking and therefore have zero-cost | 
|  | //     for this feature. | 
|  | //  2) All other builds that allow memory tracking have minimal cost as long | 
|  | //     as memory tracking has not been activated. This is facilitated by NOT | 
|  | //     using locks, at the expense of thread safety during teardown (hence the | 
|  | //     reason why you should NOT delete a memory tracker with hooks installed). | 
|  | //  3) When the memory tracking has been activated then there is a non-trivial | 
|  | //     performance cost in terms of CPU and memory for the feature. | 
|  | class MemoryTracker { | 
|  | public: | 
|  | // Gets the singleton instance of the default MemoryTracker. This | 
|  | // is created the first time it is used. | 
|  | static MemoryTracker* Get(); | 
|  |  | 
|  | MemoryTracker() {} | 
|  | virtual bool InstallGlobalTrackingHooks() = 0; | 
|  |  | 
|  | // It's recommended the MemoryTracker is never removed or deleted during the | 
|  | // runtime. | 
|  | virtual void RemoveGlobalTrackingHooks() = 0; | 
|  |  | 
|  | // Returns the total amount of bytes that are tracked. | 
|  | virtual int64_t GetTotalAllocationBytes() = 0; | 
|  | virtual int64_t GetTotalNumberOfAllocations() = 0; | 
|  |  | 
|  | // Allows probing of all memory allocations. The visitor does not need to | 
|  | // perform any locking and can allocate memory during it's operation. | 
|  | virtual void Accept(AllocationVisitor* visitor) = 0; | 
|  |  | 
|  | // Collects all memory groups that exist. The AllocationGroups lifetime | 
|  | // exists for as long as the MemoryTracker instance is alive. | 
|  | virtual void GetAllocationGroups( | 
|  | std::vector<const AllocationGroup*>* output) = 0; | 
|  |  | 
|  | // Enabled/disables memory tracking in the current thread. | 
|  | virtual void SetMemoryTrackingEnabled(bool on) = 0; | 
|  | // Returns the memory tracking state in the current thread. | 
|  | virtual bool IsMemoryTrackingEnabled() const = 0; | 
|  |  | 
|  | // Returns true if the memory was successfully tracked. | 
|  | virtual bool AddMemoryTracking(const void* memory, size_t size) = 0; | 
|  | // Returns a non-zero size if the memory was successfully removed. | 
|  | virtual size_t RemoveMemoryTracking(const void* memory) = 0; | 
|  | // Returns true if the memory has tracking. When true is returned then the | 
|  | // supplied AllocRecord is written. | 
|  | virtual bool GetMemoryTracking(const void* memory, | 
|  | AllocationRecord* record) const = 0; | 
|  | // Attaches a debug callback which fires on every new allocation that becomes | 
|  | // visible. The intended use case is to allow the developer to inspect | 
|  | // allocations that meet certain criteria. For example all allocations that | 
|  | // are of a certain size range and are allocated under a particular memory | 
|  | // scope. | 
|  | virtual void SetMemoryTrackerDebugCallback( | 
|  | MemoryTrackerDebugCallback* cb) = 0; | 
|  |  | 
|  | protected: | 
|  | virtual ~MemoryTracker() {} | 
|  |  | 
|  | SB_DISALLOW_COPY_AND_ASSIGN(MemoryTracker); | 
|  | }; | 
|  |  | 
|  | // A visitor class which is useful for inspecting data. | 
|  | class AllocationVisitor { | 
|  | public: | 
|  | // Returns true to keep visiting, otherwise abort. | 
|  | virtual bool Visit(const void* memory, | 
|  | const AllocationRecord& alloc_record) = 0; | 
|  | virtual ~AllocationVisitor() {} | 
|  | }; | 
|  |  | 
|  | // See also MemoryTracker::SetMemoryTrackerDebugCallback(...) | 
|  | // The intended use case is to allow the developer to inspect | 
|  | // allocations that meet certain criteria. For example all allocations that | 
|  | // are of a certain size range and are allocated under a particular memory | 
|  | // scope. | 
|  | class MemoryTrackerDebugCallback { | 
|  | public: | 
|  | virtual ~MemoryTrackerDebugCallback() {} | 
|  |  | 
|  | virtual void OnMemoryAllocation(const void* memory_block, | 
|  | const AllocationRecord& record, | 
|  | const CallStack& callstack) = 0; | 
|  |  | 
|  | virtual void OnMemoryDeallocation(const void* memory_block, | 
|  | const AllocationRecord& record, | 
|  | const CallStack& callstack) = 0; | 
|  | }; | 
|  |  | 
|  | }  // namespace analytics | 
|  | }  // namespace nb | 
|  |  | 
|  | #endif  // NB_MEMORY_TRACKER_H_ |