blob: 182488a4b4fc7616d884d019ba5d856874e478fc [file] [log] [blame]
/*
* 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_