blob: 1575e7b80e49f474fcc94dde95cf84c6f7cbab52 [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_IMPL_H_
#define NB_MEMORY_TRACKER_IMPL_H_
#include "nb/analytics/memory_tracker_helpers.h"
#include "nb/analytics/memory_tracker.h"
#include "nb/memory_scope.h"
#include "nb/scoped_ptr.h"
#include "nb/thread_local_object.h"
#include "starboard/configuration.h"
#include "starboard/memory_reporter.h"
#include "starboard/memory.h"
#include "starboard/mutex.h"
namespace nb {
namespace analytics {
class MemoryTrackerImpl : public MemoryTracker {
public:
typedef ConcurrentAllocationMap AllocationMapType;
MemoryTrackerImpl();
virtual ~MemoryTrackerImpl();
// MemoryTracker adapter which is compatible with the SbMemoryReporter
// interface.
SbMemoryReporter* GetMemoryReporter();
NbMemoryScopeReporter* GetMemoryScopeReporter();
AllocationGroup* GetAllocationGroup(const char* name);
// Declares the start of a memory region. After this call, all
// memory regions will be tagged with this allocation group.
// Note that AllocationGroup is a tracking characteristic and
// does not imply any sort of special allocation pool.
void PushAllocationGroupByName(const char* group_name);
void PushAllocationGroup(AllocationGroup* alloc_group);
AllocationGroup* PeekAllocationGroup();
// Ends the current memory region and the previous memory region
// is restored.
void PopAllocationGroup();
// CONTROL
//
// Adds tracking to the supplied memory pointer. An AllocationRecord is
// generated for the supplied allocation which can be queried immediately
// with GetMemoryTracking(...).
bool InstallGlobalTrackingHooks() SB_OVERRIDE {
if (global_hooks_installed_)
return true;
global_hooks_installed_ = true;
bool ok = SbMemorySetReporter(GetMemoryReporter());
ok |= NbSetMemoryScopeReporter(GetMemoryScopeReporter());
return ok;
}
void RemoveGlobalTrackingHooks() SB_OVERRIDE {
SbMemorySetReporter(NULL);
NbSetMemoryScopeReporter(NULL);
}
bool AddMemoryTracking(const void* memory, size_t size) SB_OVERRIDE;
size_t RemoveMemoryTracking(const void* memory) SB_OVERRIDE;
// Returns true if the allocation record was successfully found.
// If true then the output will be written to with the values.
// Otherwise the output is reset to the empty AllocationRecord.
bool GetMemoryTracking(const void* memory,
AllocationRecord* record) const SB_OVERRIDE;
// Thread local function to get and set the memory tracking state. When set
// to disabled then memory allocations are not recorded. However memory
// deletions are still recorded.
void SetMemoryTrackingEnabled(bool on) SB_OVERRIDE;
bool IsMemoryTrackingEnabled() const SB_OVERRIDE;
// REPORTING
//
// Total allocation bytes that have been allocated by this
// MemoryTrackerImpl.
int64_t GetTotalAllocationBytes() SB_OVERRIDE;
// Retrieves a collection of all known allocation groups. Locking is done
// internally.
void GetAllocationGroups(std::vector<const AllocationGroup*>* output)
SB_OVERRIDE;
// Retrieves a collection of all known allocation groups. Locking is done
// internally. The output is a map of names to AllocationGroups.
void GetAllocationGroups(
std::map<std::string, const AllocationGroup*>* output);
// Provides access to the internal allocations in a thread safe way.
// Allocation tracking is disabled in the current thread for the duration
// of the visitation.
void Accept(AllocationVisitor* visitor) SB_OVERRIDE;
int64_t GetTotalNumberOfAllocations() SB_OVERRIDE {
return pointer_map()->Size();
}
// TESTING.
AllocationMapType* pointer_map() { return &atomic_allocation_map_; }
void Clear();
// This is useful for debugging. Allows the developer to set a breakpoint
// and see only allocations that are in the defined allocation group. This
// is only active in the current thread.
void Debug_PushAllocationGroupBreakPointByName(const char* group_name);
void Debug_PushAllocationGroupBreakPoint(AllocationGroup* alloc_group);
void Debug_PopAllocationGroupBreakPoint();
// This is useful for testing, setting this to a thread will allow ONLY
// those allocations from the set thread.
// Setting this to kSbThreadInvalidId (default) allows all threads to report
// allocations.
void SetThreadFilter(SbThreadId tid);
bool IsCurrentThreadAllowedToReport() const;
private:
struct DisableMemoryTrackingInScope {
DisableMemoryTrackingInScope(MemoryTrackerImpl* t);
~DisableMemoryTrackingInScope();
MemoryTrackerImpl* owner_;
bool prev_value_;
};
// Disables all memory deletion in the current scope. This is used in one
// location.
struct DisableDeletionInScope {
DisableDeletionInScope(MemoryTrackerImpl* owner);
~DisableDeletionInScope();
MemoryTrackerImpl* owner_;
bool prev_state_;
};
// These are functions that are used specifically SbMemoryReporter.
static void OnMalloc(void* context, const void* memory, size_t size);
static void OnDealloc(void* context, const void* memory);
static void OnMapMem(void* context, const void* memory, size_t size);
static void OnUnMapMem(void* context, const void* memory, size_t size);
static void OnPushAllocationGroup(void* context,
NbMemoryScopeInfo* memory_scope_info);
static void OnPopAllocationGroup(void* context);
void Initialize(SbMemoryReporter* memory_reporter,
NbMemoryScopeReporter* nb_memory_scope_reporter);
void AddAllocationBytes(int64_t val);
bool MemoryDeletionEnabled() const;
void SetMemoryDeletionEnabled(bool on);
SbMemoryReporter sb_memory_tracker_;
NbMemoryScopeReporter nb_memory_scope_reporter_;
SbThreadId thread_filter_id_;
AllocationMapType atomic_allocation_map_;
AtomicStringAllocationGroupMap alloc_group_map_;
atomic_int64_t total_bytes_allocated_;
// THREAD LOCAL SECTION.
ThreadLocalBoolean memory_deletion_enabled_tls_;
ThreadLocalBoolean memory_tracking_disabled_tls_;
ThreadLocalObject<AllocationGroupStack> allocation_group_stack_tls_;
bool global_hooks_installed_;
};
// Start() is called when this object is created, and Cancel() & Join() are
// called during destruction.
class MemoryTrackerPrintThread : private SimpleThread {
public:
MemoryTrackerPrintThread(MemoryTracker* memory_tracker);
virtual ~MemoryTrackerPrintThread() SB_OVERRIDE;
// Overridden so that the thread can exit gracefully.
virtual void Cancel() SB_OVERRIDE;
virtual void Run() SB_OVERRIDE;
private:
atomic_bool finished_;
MemoryTracker* memory_tracker_;
};
} // namespace analytics
} // namespace nb
#endif // NB_MEMORY_TRACKER_IMPL_H_