mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Squash: Fix bugs
This commit is contained in:
parent
10d188faab
commit
716e578a19
382 changed files with 170096 additions and 220 deletions
399
trunk/3rdparty/gperftools-2-fit/src/heap-profile-table.h
vendored
Normal file
399
trunk/3rdparty/gperftools-2-fit/src/heap-profile-table.h
vendored
Normal file
|
@ -0,0 +1,399 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ---
|
||||
// Author: Sanjay Ghemawat
|
||||
// Maxim Lifantsev (refactoring)
|
||||
//
|
||||
|
||||
#ifndef BASE_HEAP_PROFILE_TABLE_H_
|
||||
#define BASE_HEAP_PROFILE_TABLE_H_
|
||||
|
||||
#include "addressmap-inl.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h" // for RawFD
|
||||
#include "heap-profile-stats.h"
|
||||
|
||||
// Table to maintain a heap profile data inside,
|
||||
// i.e. the set of currently active heap memory allocations.
|
||||
// thread-unsafe and non-reentrant code:
|
||||
// each instance object must be used by one thread
|
||||
// at a time w/o self-recursion.
|
||||
//
|
||||
// TODO(maxim): add a unittest for this class.
|
||||
class HeapProfileTable {
|
||||
public:
|
||||
|
||||
// Extension to be used for heap pforile files.
|
||||
static const char kFileExt[];
|
||||
|
||||
// Longest stack trace we record.
|
||||
static const int kMaxStackDepth = 32;
|
||||
|
||||
// data types ----------------------------
|
||||
|
||||
// Profile stats.
|
||||
typedef HeapProfileStats Stats;
|
||||
|
||||
// Info we can return about an allocation.
|
||||
struct AllocInfo {
|
||||
size_t object_size; // size of the allocation
|
||||
const void* const* call_stack; // call stack that made the allocation call
|
||||
int stack_depth; // depth of call_stack
|
||||
bool live;
|
||||
bool ignored;
|
||||
};
|
||||
|
||||
// Info we return about an allocation context.
|
||||
// An allocation context is a unique caller stack trace
|
||||
// of an allocation operation.
|
||||
struct AllocContextInfo : public Stats {
|
||||
int stack_depth; // Depth of stack trace
|
||||
const void* const* call_stack; // Stack trace
|
||||
};
|
||||
|
||||
// Memory (de)allocator interface we'll use.
|
||||
typedef void* (*Allocator)(size_t size);
|
||||
typedef void (*DeAllocator)(void* ptr);
|
||||
|
||||
// interface ---------------------------
|
||||
|
||||
HeapProfileTable(Allocator alloc, DeAllocator dealloc, bool profile_mmap);
|
||||
~HeapProfileTable();
|
||||
|
||||
// Collect the stack trace for the function that asked to do the
|
||||
// allocation for passing to RecordAlloc() below.
|
||||
//
|
||||
// The stack trace is stored in 'stack'. The stack depth is returned.
|
||||
//
|
||||
// 'skip_count' gives the number of stack frames between this call
|
||||
// and the memory allocation function.
|
||||
static int GetCallerStackTrace(int skip_count, void* stack[kMaxStackDepth]);
|
||||
|
||||
// Record an allocation at 'ptr' of 'bytes' bytes. 'stack_depth'
|
||||
// and 'call_stack' identifying the function that requested the
|
||||
// allocation. They can be generated using GetCallerStackTrace() above.
|
||||
void RecordAlloc(const void* ptr, size_t bytes,
|
||||
int stack_depth, const void* const call_stack[]);
|
||||
|
||||
// Record the deallocation of memory at 'ptr'.
|
||||
void RecordFree(const void* ptr);
|
||||
|
||||
// Return true iff we have recorded an allocation at 'ptr'.
|
||||
// If yes, fill *object_size with the allocation byte size.
|
||||
bool FindAlloc(const void* ptr, size_t* object_size) const;
|
||||
// Same as FindAlloc, but fills all of *info.
|
||||
bool FindAllocDetails(const void* ptr, AllocInfo* info) const;
|
||||
|
||||
// Return true iff "ptr" points into a recorded allocation
|
||||
// If yes, fill *object_ptr with the actual allocation address
|
||||
// and *object_size with the allocation byte size.
|
||||
// max_size specifies largest currently possible allocation size.
|
||||
bool FindInsideAlloc(const void* ptr, size_t max_size,
|
||||
const void** object_ptr, size_t* object_size) const;
|
||||
|
||||
// If "ptr" points to a recorded allocation and it's not marked as live
|
||||
// mark it as live and return true. Else return false.
|
||||
// All allocations start as non-live.
|
||||
bool MarkAsLive(const void* ptr);
|
||||
|
||||
// If "ptr" points to a recorded allocation, mark it as "ignored".
|
||||
// Ignored objects are treated like other objects, except that they
|
||||
// are skipped in heap checking reports.
|
||||
void MarkAsIgnored(const void* ptr);
|
||||
|
||||
// Return current total (de)allocation statistics. It doesn't contain
|
||||
// mmap'ed regions.
|
||||
const Stats& total() const { return total_; }
|
||||
|
||||
// Allocation data iteration callback: gets passed object pointer and
|
||||
// fully-filled AllocInfo.
|
||||
typedef void (*AllocIterator)(const void* ptr, const AllocInfo& info);
|
||||
|
||||
// Iterate over the allocation profile data calling "callback"
|
||||
// for every allocation.
|
||||
void IterateAllocs(AllocIterator callback) const {
|
||||
address_map_->Iterate(MapArgsAllocIterator, callback);
|
||||
}
|
||||
|
||||
// Allocation context profile data iteration callback
|
||||
typedef void (*AllocContextIterator)(const AllocContextInfo& info);
|
||||
|
||||
// Iterate over the allocation context profile data calling "callback"
|
||||
// for every allocation context. Allocation contexts are ordered by the
|
||||
// size of allocated space.
|
||||
void IterateOrderedAllocContexts(AllocContextIterator callback) const;
|
||||
|
||||
// Fill profile data into buffer 'buf' of size 'size'
|
||||
// and return the actual size occupied by the dump in 'buf'.
|
||||
// The profile buckets are dumped in the decreasing order
|
||||
// of currently allocated bytes.
|
||||
// We do not provision for 0-terminating 'buf'.
|
||||
int FillOrderedProfile(char buf[], int size) const;
|
||||
|
||||
// Cleanup any old profile files matching prefix + ".*" + kFileExt.
|
||||
static void CleanupOldProfiles(const char* prefix);
|
||||
|
||||
// Return a snapshot of the current contents of *this.
|
||||
// Caller must call ReleaseSnapshot() on result when no longer needed.
|
||||
// The result is only valid while this exists and until
|
||||
// the snapshot is discarded by calling ReleaseSnapshot().
|
||||
class Snapshot;
|
||||
Snapshot* TakeSnapshot();
|
||||
|
||||
// Release a previously taken snapshot. snapshot must not
|
||||
// be used after this call.
|
||||
void ReleaseSnapshot(Snapshot* snapshot);
|
||||
|
||||
// Return a snapshot of every non-live, non-ignored object in *this.
|
||||
// If "base" is non-NULL, skip any objects present in "base".
|
||||
// As a side-effect, clears the "live" bit on every live object in *this.
|
||||
// Caller must call ReleaseSnapshot() on result when no longer needed.
|
||||
Snapshot* NonLiveSnapshot(Snapshot* base);
|
||||
|
||||
private:
|
||||
|
||||
// data types ----------------------------
|
||||
|
||||
// Hash table bucket to hold (de)allocation stats
|
||||
// for a given allocation call stack trace.
|
||||
typedef HeapProfileBucket Bucket;
|
||||
|
||||
// Info stored in the address map
|
||||
struct AllocValue {
|
||||
// Access to the stack-trace bucket
|
||||
Bucket* bucket() const {
|
||||
return reinterpret_cast<Bucket*>(bucket_rep & ~uintptr_t(kMask));
|
||||
}
|
||||
// This also does set_live(false).
|
||||
void set_bucket(Bucket* b) { bucket_rep = reinterpret_cast<uintptr_t>(b); }
|
||||
size_t bytes; // Number of bytes in this allocation
|
||||
|
||||
// Access to the allocation liveness flag (for leak checking)
|
||||
bool live() const { return bucket_rep & kLive; }
|
||||
void set_live(bool l) {
|
||||
bucket_rep = (bucket_rep & ~uintptr_t(kLive)) | (l ? kLive : 0);
|
||||
}
|
||||
|
||||
// Should this allocation be ignored if it looks like a leak?
|
||||
bool ignore() const { return bucket_rep & kIgnore; }
|
||||
void set_ignore(bool r) {
|
||||
bucket_rep = (bucket_rep & ~uintptr_t(kIgnore)) | (r ? kIgnore : 0);
|
||||
}
|
||||
|
||||
private:
|
||||
// We store a few bits in the bottom bits of bucket_rep.
|
||||
// (Alignment is at least four, so we have at least two bits.)
|
||||
static const int kLive = 1;
|
||||
static const int kIgnore = 2;
|
||||
static const int kMask = kLive | kIgnore;
|
||||
|
||||
uintptr_t bucket_rep;
|
||||
};
|
||||
|
||||
// helper for FindInsideAlloc
|
||||
static size_t AllocValueSize(const AllocValue& v) { return v.bytes; }
|
||||
|
||||
typedef AddressMap<AllocValue> AllocationMap;
|
||||
|
||||
// Arguments that need to be passed DumpBucketIterator callback below.
|
||||
struct BufferArgs {
|
||||
BufferArgs(char* buf_arg, int buflen_arg, int bufsize_arg)
|
||||
: buf(buf_arg),
|
||||
buflen(buflen_arg),
|
||||
bufsize(bufsize_arg) {
|
||||
}
|
||||
|
||||
char* buf;
|
||||
int buflen;
|
||||
int bufsize;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BufferArgs);
|
||||
};
|
||||
|
||||
// Arguments that need to be passed DumpNonLiveIterator callback below.
|
||||
struct DumpArgs {
|
||||
DumpArgs(RawFD fd_arg, Stats* profile_stats_arg)
|
||||
: fd(fd_arg),
|
||||
profile_stats(profile_stats_arg) {
|
||||
}
|
||||
|
||||
RawFD fd; // file to write to
|
||||
Stats* profile_stats; // stats to update (may be NULL)
|
||||
};
|
||||
|
||||
// helpers ----------------------------
|
||||
|
||||
// Unparse bucket b and print its portion of profile dump into buf.
|
||||
// We return the amount of space in buf that we use. We start printing
|
||||
// at buf + buflen, and promise not to go beyond buf + bufsize.
|
||||
// We do not provision for 0-terminating 'buf'.
|
||||
//
|
||||
// If profile_stats is non-NULL, we update *profile_stats by
|
||||
// counting bucket b.
|
||||
//
|
||||
// "extra" is appended to the unparsed bucket. Typically it is empty,
|
||||
// but may be set to something like " heapprofile" for the total
|
||||
// bucket to indicate the type of the profile.
|
||||
static int UnparseBucket(const Bucket& b,
|
||||
char* buf, int buflen, int bufsize,
|
||||
const char* extra,
|
||||
Stats* profile_stats);
|
||||
|
||||
// Get the bucket for the caller stack trace 'key' of depth 'depth'
|
||||
// creating the bucket if needed.
|
||||
Bucket* GetBucket(int depth, const void* const key[]);
|
||||
|
||||
// Helper for IterateAllocs to do callback signature conversion
|
||||
// from AllocationMap::Iterate to AllocIterator.
|
||||
static void MapArgsAllocIterator(const void* ptr, AllocValue* v,
|
||||
AllocIterator callback) {
|
||||
AllocInfo info;
|
||||
info.object_size = v->bytes;
|
||||
info.call_stack = v->bucket()->stack;
|
||||
info.stack_depth = v->bucket()->depth;
|
||||
info.live = v->live();
|
||||
info.ignored = v->ignore();
|
||||
callback(ptr, info);
|
||||
}
|
||||
|
||||
// Helper to dump a bucket.
|
||||
inline static void DumpBucketIterator(const Bucket* bucket,
|
||||
BufferArgs* args);
|
||||
|
||||
// Helper for DumpNonLiveProfile to do object-granularity
|
||||
// heap profile dumping. It gets passed to AllocationMap::Iterate.
|
||||
inline static void DumpNonLiveIterator(const void* ptr, AllocValue* v,
|
||||
const DumpArgs& args);
|
||||
|
||||
// Helper for IterateOrderedAllocContexts and FillOrderedProfile.
|
||||
// Creates a sorted list of Buckets whose length is num_buckets_.
|
||||
// The caller is responsible for deallocating the returned list.
|
||||
Bucket** MakeSortedBucketList() const;
|
||||
|
||||
// Helper for TakeSnapshot. Saves object to snapshot.
|
||||
static void AddToSnapshot(const void* ptr, AllocValue* v, Snapshot* s);
|
||||
|
||||
// Arguments passed to AddIfNonLive
|
||||
struct AddNonLiveArgs {
|
||||
Snapshot* dest;
|
||||
Snapshot* base;
|
||||
};
|
||||
|
||||
// Helper for NonLiveSnapshot. Adds the object to the destination
|
||||
// snapshot if it is non-live.
|
||||
static void AddIfNonLive(const void* ptr, AllocValue* v,
|
||||
AddNonLiveArgs* arg);
|
||||
|
||||
// Write contents of "*allocations" as a heap profile to
|
||||
// "file_name". "total" must contain the total of all entries in
|
||||
// "*allocations".
|
||||
static bool WriteProfile(const char* file_name,
|
||||
const Bucket& total,
|
||||
AllocationMap* allocations);
|
||||
|
||||
// data ----------------------------
|
||||
|
||||
// Memory (de)allocator that we use.
|
||||
Allocator alloc_;
|
||||
DeAllocator dealloc_;
|
||||
|
||||
// Overall profile stats; we use only the Stats part,
|
||||
// but make it a Bucket to pass to UnparseBucket.
|
||||
Bucket total_;
|
||||
|
||||
bool profile_mmap_;
|
||||
|
||||
// Bucket hash table for malloc.
|
||||
// We hand-craft one instead of using one of the pre-written
|
||||
// ones because we do not want to use malloc when operating on the table.
|
||||
// It is only few lines of code, so no big deal.
|
||||
Bucket** bucket_table_;
|
||||
int num_buckets_;
|
||||
|
||||
// Map of all currently allocated objects and mapped regions we know about.
|
||||
AllocationMap* address_map_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(HeapProfileTable);
|
||||
};
|
||||
|
||||
class HeapProfileTable::Snapshot {
|
||||
public:
|
||||
const Stats& total() const { return total_; }
|
||||
|
||||
// Report anything in this snapshot as a leak.
|
||||
// May use new/delete for temporary storage.
|
||||
// If should_symbolize is true, will fork (which is not threadsafe)
|
||||
// to turn addresses into symbol names. Set to false for maximum safety.
|
||||
// Also writes a heap profile to "filename" that contains
|
||||
// all of the objects in this snapshot.
|
||||
void ReportLeaks(const char* checker_name, const char* filename,
|
||||
bool should_symbolize);
|
||||
|
||||
// Report the addresses of all leaked objects.
|
||||
// May use new/delete for temporary storage.
|
||||
void ReportIndividualObjects();
|
||||
|
||||
bool Empty() const {
|
||||
return (total_.allocs == 0) && (total_.alloc_size == 0);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class HeapProfileTable;
|
||||
|
||||
// Total count/size are stored in a Bucket so we can reuse UnparseBucket
|
||||
Bucket total_;
|
||||
|
||||
// We share the Buckets managed by the parent table, but have our
|
||||
// own object->bucket map.
|
||||
AllocationMap map_;
|
||||
|
||||
Snapshot(Allocator alloc, DeAllocator dealloc) : map_(alloc, dealloc) {
|
||||
memset(&total_, 0, sizeof(total_));
|
||||
}
|
||||
|
||||
// Callback used to populate a Snapshot object with entries found
|
||||
// in another allocation map.
|
||||
inline void Add(const void* ptr, const AllocValue& v) {
|
||||
map_.Insert(ptr, v);
|
||||
total_.allocs++;
|
||||
total_.alloc_size += v.bytes;
|
||||
}
|
||||
|
||||
// Helpers for sorting and generating leak reports
|
||||
struct Entry;
|
||||
struct ReportState;
|
||||
static void ReportCallback(const void* ptr, AllocValue* v, ReportState*);
|
||||
static void ReportObject(const void* ptr, AllocValue* v, char*);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Snapshot);
|
||||
};
|
||||
|
||||
#endif // BASE_HEAP_PROFILE_TABLE_H_
|
Loading…
Add table
Add a link
Reference in a new issue