Ticket #187: profiler-memtracker.patch

File profiler-memtracker.patch, 7.7 KB (added by Markus, 11 years ago)
  • trunk/source/ps/Profile.cpp

    diff -Nur a/trunk/source/ps/Profile.cpp b/trunk/source/ps/Profile.cpp
    a b  
    3838#endif
    3939
    4040#include <numeric>
     41#include <map>
    4142
    4243///////////////////////////////////////////////////////////////////////////////////////////////
    4344// CProfileNodeTable
     
    8384            columns.push_back(ProfileColumn("calls/turn", 80));
    8485            columns.push_back(ProfileColumn("msec/turn", 80));
    8586            columns.push_back(ProfileColumn("mallocs/turn", 80));
     87            columns.push_back(ProfileColumn("alloc'd mem", 80));
    8688        }
    8789    };
    8890   
     
    160162        double unlogged_time_turn = node->GetTurnTime();
    161163        double unlogged_mallocs_frame = node->GetFrameMallocs();
    162164        double unlogged_mallocs_turn = node->GetTurnMallocs();
     165        double unlogged_alloc_mem = node->GetAllocMem();
    163166        CProfileNode::const_profile_iterator it;
    164167
    165168        for (it = node->GetChildren()->begin(); it != node->GetChildren()->end(); ++it)
     
    168171            unlogged_time_turn -= (*it)->GetTurnTime();
    169172            unlogged_mallocs_frame -= (*it)->GetFrameMallocs();
    170173            unlogged_mallocs_turn -= (*it)->GetTurnMallocs();
     174            unlogged_alloc_mem -= (*it)->GetAllocMem();
    171175        }
    172176        for (it = node->GetScriptChildren()->begin(); it != node->GetScriptChildren()->end(); ++it)
    173177        {
     
    175179            unlogged_time_turn -= (*it)->GetTurnTime();
    176180            unlogged_mallocs_frame -= (*it)->GetFrameMallocs();
    177181            unlogged_mallocs_turn -= (*it)->GetTurnMallocs();
     182            unlogged_alloc_mem -= (*it)->GetAllocMem();
    178183        }
    179184       
    180185        // The root node can't easily count per-turn values (since Turn isn't called until
     
    193198            sprintf_s(buf, ARRAY_SIZE(buf), "%.3f", unlogged_time_turn * 1000.f);
    194199        else if (col == 6)
    195200            sprintf_s(buf, ARRAY_SIZE(buf), "%.1f", unlogged_mallocs_turn);
     201        else if (col == 7) {
     202            double d = unlogged_alloc_mem;
     203            if (d >= 10.0 * 1024 * 1024)
     204                sprintf_s(buf, ARRAY_SIZE(buf), "%.1f MiB", d / 1024.0 / 1024.0);
     205            else if (d >= 10.0 * 1024)
     206                sprintf_s(buf, ARRAY_SIZE(buf), "%.1f KiB", d / 1024.0);
     207            else
     208                sprintf_s(buf, ARRAY_SIZE(buf), "%.1f B", d);
     209        }
    196210       
    197211        return CStr(buf);
    198212    }
     
    221235    case 6:
    222236        sprintf_s(buf, ARRAY_SIZE(buf), "%.1f", child->GetTurnMallocs());
    223237        break;
     238    case 7:
     239    {
     240        double d = child->GetAllocMem();
     241        if (d >= 10.0 * 1024 * 1024)
     242            sprintf_s(buf, ARRAY_SIZE(buf), "%.1f MiB", d / 1024.0 / 1024.0);
     243        else if (d >= 10.0 * 1024)
     244            sprintf_s(buf, ARRAY_SIZE(buf), "%.1f KiB", d / 1024.0);
     245        else
     246            sprintf_s(buf, ARRAY_SIZE(buf), "%.1f B", d);
     247        break;
     248    }
    224249    }
    225250    return CStr(buf);
    226251}
     
    264289    name = _name;
    265290    recursion = 0;
    266291
     292    pthread_mutex_init(&alloc_mem_mutex, NULL);
     293    alloc_mem = 0;
     294
    267295    Reset();
    268296
    269297    parent = _parent;
     
    280308        delete( *it );
    281309   
    282310    delete display_table;
     311   
     312    pthread_mutex_destroy(&alloc_mem_mutex);
    283313}
    284314
    285315template<typename T>
     
    504534
    505535//#define ALLOC_DEBUG
    506536
     537std::map<void*, std::pair<CProfileNode*, size_t> > memtracker_map;
     538static pthread_mutex_t memtracker_map_mutex = PTHREAD_MUTEX_INITIALIZER;
     539
     540static volatile pthread_t memtracker_access;
     541static volatile bool memtracker_access_valid = false;
     542static pthread_mutex_t memtracker_access_mutex = PTHREAD_MUTEX_INITIALIZER;
     543
     544static volatile bool memtracker_enabled = false;
     545
     546static void memtracker_enable(bool b)
     547{
     548    memtracker_enabled = b;
     549    if (!memtracker_enabled) {
     550        debug_printf(L"Disabling breaks memory-tracking\n");
     551        pthread_mutex_lock(&memtracker_map_mutex);
     552        memtracker_map.clear();
     553        pthread_mutex_unlock(&memtracker_map_mutex);
     554    }
     555}
     556
     557void memtracker_update(void *o, void *n, size_t s)
     558{
     559    if (!memtracker_enabled)
     560        return;
     561
     562    while (true) {
     563        pthread_mutex_lock(&memtracker_access_mutex);
     564        if (!memtracker_access_valid) { // noone here, register
     565            memtracker_access = pthread_self();
     566            memtracker_access_valid = true;
     567            pthread_mutex_unlock(&memtracker_access_mutex);
     568            break;
     569        } else if (pthread_equal(memtracker_access, pthread_self())) { // same thread, recursiv -> ignore
     570            pthread_mutex_unlock(&memtracker_access_mutex);
     571            return;
     572        } else // other thread, spinlock
     573            pthread_mutex_unlock(&memtracker_access_mutex);
     574    }
     575
     576    pthread_mutex_lock(&memtracker_map_mutex);
     577    if (o) {
     578        if (memtracker_map.count(o)) {
     579            memtracker_map[o].first->RemoveAllocMem(memtracker_map[o].second);
     580            memtracker_map.erase(o);
     581        }
     582    }
     583    if (n) {
     584        if (CProfileManager::IsInitialised() && ThreadUtil::IsMainThread()) {
     585            CProfileNode* node = CProfileManager::GetSingleton().GetCurrentWritable();
     586            if (node) {
     587                memtracker_map[n] = std::pair<CProfileNode*, size_t>(node, s);
     588                node->AddAllocMem(s);
     589            }
     590        }
     591    }
     592    pthread_mutex_unlock(&memtracker_map_mutex);
     593   
     594    pthread_mutex_lock(&memtracker_access_mutex);
     595    memtracker_access_valid = false;
     596    pthread_mutex_unlock(&memtracker_access_mutex);
     597}
     598
    507599void* malloc(size_t sz)
    508600{
    509601    cpu_AtomicAdd(&alloc_count, 1);
     
    518610#ifdef ALLOC_DEBUG
    519611    printf("### malloc(%d) = %p\n", sz, ret);
    520612#endif
     613
     614    memtracker_update(0, ret, sz);
     615
    521616    return ret;
    522617}
    523618
     
    535630#ifdef ALLOC_DEBUG
    536631    printf("### realloc(%p, %d) = %p\n", ptr, sz, ret);
    537632#endif
     633
     634    memtracker_update(ptr, ret, sz);
     635
    538636    return ret;
    539637}
    540638
     
    561659#ifdef ALLOC_DEBUG
    562660    printf("### calloc(%d, %d) = %p\n", nm, sz, ret);
    563661#endif
     662
     663    memtracker_update(0, ret, sz*nm);
     664
    564665    return ret;
    565666}
    566667
     
    577678#ifdef ALLOC_DEBUG
    578679    printf("### free(%p)\n", ptr);
    579680#endif
     681
     682    memtracker_update(ptr, 0, 0);
    580683}
    581684
    582685static void alloc_hook_initialize()
     
    626729    return true;
    627730}
    628731
     732double CProfileNode::GetAllocMem()
     733{
     734    pthread_mutex_lock(&alloc_mem_mutex);
     735    long tmp = alloc_mem;
     736    pthread_mutex_unlock(&alloc_mem_mutex);
     737
     738    std::vector<CProfileNode*>::const_iterator it;
     739    for (it = children.begin(); it != children.end(); ++it )
     740        tmp += (*it)->GetAllocMem();
     741    for (it = script_children.begin(); it != script_children.end(); ++it )
     742        tmp += (*it)->GetAllocMem();
     743
     744    return tmp;
     745}
     746
    629747CProfileManager::CProfileManager() :
    630748    root(NULL), current(NULL), needs_structural_reset(false)
    631749{
     
    634752
    635753CProfileManager::~CProfileManager()
    636754{
     755#if defined(USE_GLIBC_MALLOC_OVERRIDE)
     756    memtracker_enable(false);
     757#endif
    637758    delete root;
    638759}
    639760
     
    698819
    699820void CProfileManager::PerformStructuralReset()
    700821{
     822#if defined(USE_GLIBC_MALLOC_OVERRIDE)
     823    memtracker_enable(false);
     824#endif
    701825    delete root;
    702826    root = new CProfileNode("root", NULL);
    703827    root->Call();
    704828    current = root;
    705829    g_ProfileViewer.AddRootTable(root->display_table, true);
     830#if defined(USE_GLIBC_MALLOC_OVERRIDE)
     831    memtracker_enable(true);
     832#endif
    706833}
  • trunk/source/ps/Profile.h

    diff -Nur a/trunk/source/ps/Profile.h b/trunk/source/ps/Profile.h
    a b  
    6565    double start;
    6666    long start_mallocs;
    6767    int recursion;
     68    long alloc_mem;
     69   
     70    pthread_mutex_t alloc_mem_mutex;
    6871
    6972    CProfileNode* parent;
    7073    std::vector<CProfileNode*> children;
     
    8689    double GetTurnTime() const;
    8790    double GetFrameMallocs() const;
    8891    double GetTurnMallocs() const;
     92    double GetAllocMem();
     93   
     94    void RemoveAllocMem(size_t s) { pthread_mutex_lock(&alloc_mem_mutex); alloc_mem -= s; pthread_mutex_unlock(&alloc_mem_mutex); }
     95    void AddAllocMem(size_t s) { pthread_mutex_lock(&alloc_mem_mutex); alloc_mem += s; pthread_mutex_unlock(&alloc_mem_mutex); }
    8996
    9097    const CProfileNode* GetChild( const char* name ) const;
    9198    const CProfileNode* GetScriptChild( const char* name ) const;
     
    141148    void StructuralReset();
    142149
    143150    inline const CProfileNode* GetCurrent() { return( current ); }
     151    inline CProfileNode* GetCurrentWritable() { return( current ); }
    144152    inline const CProfileNode* GetRoot() { return( root ); }
    145153};
    146154