PageRenderTime 38ms CodeModel.GetById 21ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llallocator_heap_profile.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 147 lines | 89 code | 25 blank | 33 comment | 35 complexity | 4fee3ea9d5adb9c3b7849fad882437bb MD5 | raw file
  1/** 
  2 * @file llallocator_heap_profile.cpp
  3 * @brief Implementation of the parser for tcmalloc heap profile data.
  4 * @author Brad Kittenbrink
  5 *
  6 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  7 * Second Life Viewer Source Code
  8 * Copyright (C) 2010, Linden Research, Inc.
  9 * 
 10 * This library is free software; you can redistribute it and/or
 11 * modify it under the terms of the GNU Lesser General Public
 12 * License as published by the Free Software Foundation;
 13 * version 2.1 of the License only.
 14 * 
 15 * This library is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 18 * Lesser General Public License for more details.
 19 * 
 20 * You should have received a copy of the GNU Lesser General Public
 21 * License along with this library; if not, write to the Free Software
 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 23 * 
 24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 25 * $/LicenseInfo$
 26 */
 27
 28#include "linden_common.h"
 29#include "llallocator_heap_profile.h"
 30
 31#if LL_MSVC
 32// disable warning about boost::lexical_cast returning uninitialized data
 33// when it fails to parse the string
 34#pragma warning (disable:4701)
 35#pragma warning (disable:4702)
 36#endif
 37
 38#include <boost/algorithm/string/split.hpp>
 39#include <boost/bind.hpp>
 40#include <boost/lexical_cast.hpp>
 41#include <boost/range/iterator_range.hpp>
 42
 43static const std::string HEAP_PROFILE_MAGIC_STR = "heap profile:";
 44
 45static bool is_separator(char c)
 46{
 47    return isspace(c) || c == '[' || c == ']' || c == ':';
 48}
 49
 50void LLAllocatorHeapProfile::parse(std::string const & prof_text)
 51{
 52    // a typedef for handling a token in the string buffer
 53    // it's a begin/end pair of string::const_iterators
 54    typedef boost::iterator_range<std::string::const_iterator> range_t;
 55
 56    mLines.clear();
 57
 58    if(prof_text.compare(0, HEAP_PROFILE_MAGIC_STR.length(), HEAP_PROFILE_MAGIC_STR) != 0)
 59    {
 60        // *TODO - determine if there should be some better error state than
 61        // mLines being empty. -brad
 62        llwarns << "invalid heap profile data passed into parser." << llendl;
 63        return;
 64    }
 65
 66    std::vector< range_t > prof_lines;
 67
 68    std::string::const_iterator prof_begin = prof_text.begin() + HEAP_PROFILE_MAGIC_STR.length();
 69
 70	range_t prof_range(prof_begin, prof_text.end());
 71    boost::algorithm::split(prof_lines,
 72        prof_range,
 73        boost::bind(std::equal_to<llwchar>(), '\n', _1));
 74
 75    std::vector< range_t >::const_iterator i;
 76    for(i = prof_lines.begin(); i != prof_lines.end() && !i->empty(); ++i)
 77    {
 78        range_t const & line_text = *i;
 79
 80        std::vector<range_t> line_elems;
 81
 82        boost::algorithm::split(line_elems,
 83            line_text,
 84            is_separator);
 85
 86        std::vector< range_t >::iterator j;
 87        j = line_elems.begin();
 88
 89        while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
 90        llassert_always(j != line_elems.end());
 91        U32 live_count = boost::lexical_cast<U32>(*j);
 92        ++j;
 93
 94        while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
 95        llassert_always(j != line_elems.end());
 96        U64 live_size = boost::lexical_cast<U64>(*j);
 97        ++j;
 98
 99        while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
100        llassert_always(j != line_elems.end());
101        U32 tot_count = boost::lexical_cast<U32>(*j);
102        ++j;
103
104        while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
105        llassert_always(j != line_elems.end());
106        U64 tot_size = boost::lexical_cast<U64>(*j);
107        ++j;
108
109        while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
110	llassert(j != line_elems.end());
111        if (j != line_elems.end())
112	{
113		++j; // skip the '@'
114
115		mLines.push_back(line(live_count, live_size, tot_count, tot_size));
116		line & current_line = mLines.back();
117		
118		for(; j != line_elems.end(); ++j)
119		{
120			if(!j->empty())
121			{
122				U32 marker = boost::lexical_cast<U32>(*j);
123				current_line.mTrace.push_back(marker);
124			}
125		}
126	}
127    }
128    // *TODO - parse MAPPED_LIBRARIES section here if we're ever interested in it
129}
130
131void LLAllocatorHeapProfile::dump(std::ostream & out) const
132{
133    lines_t::const_iterator i;
134    for(i = mLines.begin(); i != mLines.end(); ++i)
135    {
136        out << i->mLiveCount << ": " << i->mLiveSize << '[' << i->mTotalCount << ": " << i->mTotalSize << "] @";
137
138        stack_trace::const_iterator j;
139        for(j = i->mTrace.begin(); j != i->mTrace.end(); ++j)
140        {
141            out << ' ' << *j;
142        }
143        out << '\n';
144    }
145    out.flush();
146}
147