From 77a4df34ffb3a5a6a13ac628433c8549c5216be4 Mon Sep 17 00:00:00 2001 From: zd-double Date: Tue, 29 Nov 2016 00:01:54 +0800 Subject: [PATCH 1/3] Add memory profiling --- src/sofa/pbrpc/profiling.cc | 372 ++++++++++++++++++-- src/sofa/pbrpc/profiling.h | 19 +- src/sofa/pbrpc/profiling_linker.h | 11 +- src/sofa/pbrpc/tcmalloc_extension_helper.cc | 321 +++++++++++++++++ src/sofa/pbrpc/web_service.cc | 30 +- 5 files changed, 708 insertions(+), 45 deletions(-) create mode 100644 src/sofa/pbrpc/tcmalloc_extension_helper.cc diff --git a/src/sofa/pbrpc/profiling.cc b/src/sofa/pbrpc/profiling.cc index baf3799..1092683 100644 --- a/src/sofa/pbrpc/profiling.cc +++ b/src/sofa/pbrpc/profiling.cc @@ -6,14 +6,28 @@ #include #include #include +#include +#include #include #include #include #include +#include + +#ifndef SOFA_PBRPC_PROFILING_SAMPLE_TIME +#define SOFA_PBRPC_PROFILING_SAMPLE_TIME 10 +#endif + +bool PROFILING_LINKER_FALSE = false; + +void __attribute__((weak)) TCMallocGetHeapSample(std::string* writer); namespace sofa { namespace pbrpc { +static const std::string CPU_PROFILING_PATH = "/rpc_profiling/cpu/"; +static const std::string MEMORY_PROFILING_PATH = "/rpc_profiling/memory/"; + extern "C" { int __attribute__((weak)) ProfilerStart(const char* fname); @@ -42,6 +56,53 @@ static bool Mkdir(const std::string& path) return false; } +static void ListFile(const std::string& path, std::set& files) +{ + struct dirent* dir_entry; + DIR* dir = opendir(path.c_str()); + if (dir == NULL) + { +#if defined( LOG ) + LOG(ERROR) << "ListFile(): open dir {" + << path << "} failed: " << strerror(errno); +#else + SLOG(ERROR, "ListFile(): open dir {%s} failed: %s", + path.c_str(), strerror(errno)); +#endif + return; + } + while ((dir_entry = readdir(dir)) != NULL) + { + if (dir_entry->d_type == DT_REG) + { + files.insert(dir_entry->d_name); + } + } +} + +static bool WriteFile(const std::string& path, const char* buffer, size_t size) +{ + if (buffer == NULL) + { + return false; + } + FILE* fp = fopen(path.c_str(), "w"); + if (fp == NULL) + { +#if defined( LOG ) + LOG(ERROR) << "WriteFile(): open file {" + << path << "} failed: " << strerror(errno); +#else + SLOG(ERROR, "WriteFile(): open file {%s} failed: %s", + path.c_str(), strerror(errno)); +#endif + return false; + } + fwrite(buffer, size, 1, fp); + fclose(fp); + return true; +} + static bool IsFileExist(const std::string& path) { std::ifstream ifs(path.c_str()); @@ -74,26 +135,60 @@ static std::string exec(const std::string& cmd) void Profiling::CpuProfilingFunc() { - // TODO - bool ret = Mkdir(_dir.path + "/rpc_profiling"); - if (ret == false) + if (!IsFileExist(_dir.path + CPU_PROFILING_PATH)) { - return; + bool ret = Mkdir(_dir.path + CPU_PROFILING_PATH); + if (ret == false) + { + return; + } } - std::string path = _dir.path + "/rpc_profiling/tmp.prof"; + struct timeval tval; + gettimeofday(&tval, NULL); + std::string path = _dir.path + + CPU_PROFILING_PATH + "tmp." + + StringUtils::uint64_to_string(tval.tv_sec) + + ".prof"; ProfilerStart(path.c_str()); - sleep(10); + sleep(SOFA_PBRPC_PROFILING_SAMPLE_TIME); ProfilerStop(); - _is_profiling = false; + _is_cpu_profiling = false; } void Profiling::MemoryProfilingFunc() { - // TODO + if (!IsFileExist(_dir.path + MEMORY_PROFILING_PATH)) + { + bool ret = Mkdir(_dir.path + MEMORY_PROFILING_PATH); + if (ret == false) + { + return; + } + } + struct timeval tval; + gettimeofday(&tval, NULL); + std::string path = _dir.path + + MEMORY_PROFILING_PATH + "tmp." + + StringUtils::uint64_to_string(tval.tv_sec) + + ".heap"; + + std::string writer; + TCMallocGetHeapSample(&writer); + if (!WriteFile(path, writer.c_str(), writer.size())) + { +#if defined( LOG ) + LOG(ERROR) << "WriteFile(): write file {" << path << "} failed"; +#else + SLOG(ERROR, "WriteFile(): write file {%s} failed", path.c_str()); +#endif + return; + } + _is_mem_profiling = false; } Profiling::Profiling() -: _is_profiling(false) +: _is_cpu_profiling(false) + , _is_mem_profiling(false) , _is_initialized(false) { _profiling_thread_group.reset(new ThreadGroupImpl( @@ -109,6 +204,11 @@ int Profiling::Init() if (!_profiling_thread_group->start()) { +#if defined( LOG ) + LOG(ERROR) << "Init(): start profiling thread group failed"; +#else + SLOG(ERROR, "Init(): start profiling thread group failed"); +#endif _profiling_thread_group.reset(); return -1; } @@ -119,19 +219,32 @@ int Profiling::Init() ssize_t r = readlink(link, buf, PATH_MAX); if (r == -1) { +#if defined( LOG ) + LOG(ERROR) << "Init(): read executed file path failed"; +#else + SLOG(ERROR, "Init(): read executed file path failed"); +#endif return -1; } - // TODO std::string path(buf); int pos = path.rfind("/"); if (pos < 0) { +#if defined( LOG ) + LOG(ERROR) << "Init(): bad executed file path: " << path; +#else + SLOG(ERROR, "Init(): bad executed file path: %s", path.c_str()); +#endif return -1; } _dir.path = path.substr(0, pos); _dir.name = path.substr(pos + 1, path.size()); + if (!Mkdir(_dir.path + "/rpc_profiling")) + { + return -1; + } _is_initialized = true; return 0; } @@ -146,7 +259,9 @@ Profiling::~Profiling() } std::string Profiling::ProfilingPage(ProfilingType profiling_type, - DataType data_type) + DataType data_type, + std::string& view_prof, + std::string& base_prof) { std::ostringstream oss; oss << "

Sofa-pbrpc Profiling

"; @@ -160,23 +275,42 @@ std::string Profiling::ProfilingPage(ProfilingType profiling_type, } } - switch (profiling_type) + switch (profiling_type) { case CPU: if (data_type == GRAPH) { oss.str(""); oss.clear(); - std::string dot = - exec("perl " + _dir.path + "/rpc_profiling/pprof.perl --dot " - + _dir.path + "/"+ _dir.name + " " + _dir.path - + "/rpc_profiling/tmp.prof"); + std::string cmd = "perl " + _dir.path + "/rpc_profiling/pprof.perl --dot " + + _dir.path + "/" + _dir.name + " " + _dir.path + + CPU_PROFILING_PATH + view_prof; + if (!base_prof.empty()) + { + cmd.append(" --base " + _dir.path + CPU_PROFILING_PATH + base_prof); + } + std::string dot = exec(cmd); oss << dot; return oss.str(); } + else if (data_type == CLEANUP) + { + std::set profiling_set; + ListFile(_dir.path + CPU_PROFILING_PATH, profiling_set); + for (std::set::iterator it = profiling_set.begin(); + it != profiling_set.end(); ++it) + { + ::remove(std::string(_dir.path + CPU_PROFILING_PATH + *it).c_str()); + } + oss << ShowResult(profiling_type, view_prof, base_prof); + } + else if (data_type == DIFF) + { + oss << ShowResult(profiling_type, view_prof, base_prof); + } else { - Status ret = DoCpuProfiling(data_type); + Status ret = DoCpuProfiling(data_type, view_prof); if (ret == DISABLE) { oss << "

To enable profiling, please add compile and link options when compiling binary:

"; @@ -198,7 +332,7 @@ std::string Profiling::ProfilingPage(ProfilingType profiling_type, } else if (ret == FINISHED) { - oss << ShowResult(); + oss << ShowResult(profiling_type, view_prof, base_prof); } else { @@ -209,8 +343,69 @@ std::string Profiling::ProfilingPage(ProfilingType profiling_type, } break; case MEMORY: - // TODO - oss << "

Memory profiling not supported now

"; + if (data_type == GRAPH) + { + oss.str(""); + oss.clear(); + std::string cmd = "perl " + _dir.path + "/rpc_profiling/pprof.perl --dot " + + _dir.path + "/" + _dir.name + " " + _dir.path + + MEMORY_PROFILING_PATH + view_prof; + if (!base_prof.empty()) + { + cmd.append(" --base " + _dir.path + MEMORY_PROFILING_PATH + base_prof); + } + std::string dot = exec(cmd); + oss << dot; + return oss.str(); + } + else if (data_type == CLEANUP) + { + std::set profiling_set; + ListFile(_dir.path + MEMORY_PROFILING_PATH, profiling_set); + for (std::set::iterator it = profiling_set.begin(); + it != profiling_set.end(); ++it) + { + ::remove(std::string(_dir.path + MEMORY_PROFILING_PATH + *it).c_str()); + } + oss << ShowResult(profiling_type, view_prof, base_prof); + } + else if (data_type == DIFF) + { + oss << ShowResult(profiling_type, view_prof, base_prof); + } + else + { + Status ret = DoMemoryProfiling(data_type, view_prof); + if (ret == DISABLE) + { + oss << "

To enable memory profiling, please add compile and link options when compiling binary:

"; + oss << "
    "; + oss << "
  1. Install gperftools:
  2. "; + oss << "
      "; + oss << "
    • For Ubuntu: sudo apt-get install libgoogle-perftools-dev
    • "; + oss << "
    • For CentOS: sudo yum install google-perftools-devel
    • "; + oss << "
    "; + oss << "
  3. Add '-DSOFA_PBRPC_PROFILING' to CXXFLAGS
  4. "; + oss << "
  5. Add '-ltcmalloc_and_profiler' to LDFLAGS
  6. "; + oss << "
"; + } + else if (ret == PROFILING) + { + oss << "

Profiling is in processing, please wait ...

"; + oss << ""; + } + else if (ret == FINISHED) + { + oss << ShowResult(profiling_type, view_prof, base_prof); + } + else + { + oss << "

Profiling is starting, please wait ...

"; + oss << ""; + } + } break; default: oss << "
"; @@ -224,30 +419,31 @@ std::string Profiling::ProfilingPage(ProfilingType profiling_type, return oss.str(); } -Profiling::Status Profiling::DoCpuProfiling(DataType data_type) +Profiling::Status Profiling::DoCpuProfiling(DataType data_type, std::string& profiling_file) { if (ProfilerStart == NULL) { return DISABLE; } - if (_is_profiling == true) + if (_is_cpu_profiling == true) { return PROFILING; } - if (data_type == NEW_GRAPH) + std::set profiling_set; + ListFile(_dir.path + CPU_PROFILING_PATH, profiling_set); + + if (profiling_file == "default" && !profiling_set.empty() && data_type != NEW_GRAPH) { - std::string profiling_path(_dir.path + "/rpc_profiling/tmp.prof"); - ::remove(profiling_path.c_str()); + profiling_file = *(profiling_set.rbegin()); + return FINISHED; } - - if (IsFileExist(_dir.path + "/rpc_profiling/tmp.prof")) + if (IsFileExist(_dir.path + CPU_PROFILING_PATH + profiling_file)) { return FINISHED; } - - _is_profiling = true; + _is_cpu_profiling = true; google::protobuf::Closure* done = sofa::pbrpc::NewClosure(Profiling::Instance(), &Profiling::CpuProfilingFunc); @@ -255,7 +451,9 @@ Profiling::Status Profiling::DoCpuProfiling(DataType data_type) return OK; } -std::string Profiling::ShowResult() +std::string Profiling::ShowResult(ProfilingType profiling_type, + const std::string& view_prof, + const std::string& base_prof) { std::ostringstream oss; std::string path = _dir.path + "/rpc_profiling/pprof.perl"; @@ -266,20 +464,98 @@ std::string Profiling::ShowResult() ofs.close(); } + std::string profiling_type_str; + std::string profiling_path; + if (profiling_type == CPU) + { + profiling_type_str = "cpu"; + profiling_path = _dir.path + CPU_PROFILING_PATH; + } + else if (profiling_type == MEMORY) + { + profiling_type_str = "memory"; + profiling_path = _dir.path + MEMORY_PROFILING_PATH; + } + else + { + profiling_type_str = ""; + } + + std::set profiling_set; + ListFile(profiling_path, profiling_set); + oss << ""; oss << ""; oss << ""; + oss << ""; oss << ""; - oss << ""; + oss << ""; + + oss << ""; + oss << "
exec path:[" << _dir.path << "]
"; oss << "
exec binary:[" << _dir.name << "]
"; + oss << "

"; + oss << "
View 
"; + oss << ""; + oss << "
Diff 
"; + oss << ""; + oss << "
"; oss << ""; @@ -287,10 +563,36 @@ std::string Profiling::ShowResult() return oss.str(); } -int Profiling::DoMemoryProfiling() +Profiling::Status Profiling::DoMemoryProfiling(DataType data_type, std::string& profiling_file) { - // TODO - return 0; + if (TCMallocGetHeapSample == NULL) + { + return DISABLE; + } + + if (_is_mem_profiling == true) + { + return PROFILING; + } + + std::set profiling_set; + ListFile(_dir.path + MEMORY_PROFILING_PATH, profiling_set); + + if (profiling_file == "default" && !profiling_set.empty() && data_type != NEW_GRAPH) + { + profiling_file = *(profiling_set.rbegin()); + return FINISHED; + } + if (IsFileExist(_dir.path + MEMORY_PROFILING_PATH + profiling_file)) + { + return FINISHED; + } + _is_mem_profiling = true; + google::protobuf::Closure* done = + sofa::pbrpc::NewClosure(Profiling::Instance(), + &Profiling::MemoryProfilingFunc); + _profiling_thread_group->post(done); + return OK; } Profiling* Profiling::Instance() diff --git a/src/sofa/pbrpc/profiling.h b/src/sofa/pbrpc/profiling.h index f6a27d2..2ae0a20 100644 --- a/src/sofa/pbrpc/profiling.h +++ b/src/sofa/pbrpc/profiling.h @@ -26,7 +26,9 @@ class Profiling { PAGE = 1, GRAPH = 2, - NEW_GRAPH = 3 + NEW_GRAPH = 3, + DIFF = 4, + CLEANUP = 5 }; enum Status @@ -38,11 +40,13 @@ class Profiling }; std::string ProfilingPage(ProfilingType profiling_type, - DataType data_type); + DataType data_type, + std::string& profiling_file, + std::string& profiling_base); - Status DoCpuProfiling(DataType data_type); + Status DoCpuProfiling(DataType data_type, std::string& profiling_file); - int DoMemoryProfiling(); + Status DoMemoryProfiling(DataType data_type, std::string& profiling_file); static Profiling* Instance(); @@ -57,7 +61,8 @@ class Profiling void MemoryProfilingFunc(); - std::string ShowResult(); + std::string ShowResult(ProfilingType profiling_type, + const std::string& profiling_file, const std::string& profiling_base); static void InitProfiling(); @@ -70,7 +75,9 @@ class Profiling }; private: - volatile bool _is_profiling; + volatile bool _is_cpu_profiling; + + volatile bool _is_mem_profiling; volatile bool _is_initialized; diff --git a/src/sofa/pbrpc/profiling_linker.h b/src/sofa/pbrpc/profiling_linker.h index cfc0221..6f83c64 100644 --- a/src/sofa/pbrpc/profiling_linker.h +++ b/src/sofa/pbrpc/profiling_linker.h @@ -3,17 +3,24 @@ #if defined(SOFA_PBRPC_PROFILING) #include +void TCMallocGetHeapSample(std::string* writer); #endif // SOFA_PBRPC_PROFILING +extern bool PROFILING_LINKER_FALSE; + class ProfilingLinker { public: ProfilingLinker() { -#if defined(SOFA_PBRPC_PROFILING) // make libprofiler be linked - (void)ProfilingIsEnabledForAllThreads(); + if (PROFILING_LINKER_FALSE != false) + { +#if defined(SOFA_PBRPC_PROFILING) + ProfilerStart(NULL); + TCMallocGetHeapSample(NULL); #endif // SOFA_PBRPC_PROFILING + } } }; diff --git a/src/sofa/pbrpc/tcmalloc_extension_helper.cc b/src/sofa/pbrpc/tcmalloc_extension_helper.cc new file mode 100644 index 0000000..1e10d28 --- /dev/null +++ b/src/sofa/pbrpc/tcmalloc_extension_helper.cc @@ -0,0 +1,321 @@ +// This file pastes google/malloc_extension.h and implements +// TCMallocGetHeapSample in the last sections. + +// Copyright (c) 2005, 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 +// +// Extra extensions exported by some malloc implementations. These +// extensions are accessed through a virtual base class so an +// application can link against a malloc that does not implement these +// extensions, and it will get default versions that do nothing. +// +// NOTE FOR C USERS: If you wish to use this functionality from within +// a C program, see malloc_extension_c.h. + +#include +// I can't #include config.h in this public API file, but I should +// really use configure (and make malloc_extension.h a .in file) to +// figure out if the system has stdint.h or not. But I'm lazy, so +// for now I'm assuming it's a problem only with MSVC. +#ifndef _MSC_VER +#include +#endif +#include +#include + +// Annoying stuff for windows -- makes sure clients can import these functions +#ifndef PERFTOOLS_DLL_DECL +# ifdef _WIN32 +# define PERFTOOLS_DLL_DECL __declspec(dllimport) +# else +# define PERFTOOLS_DLL_DECL +# endif +#endif + +static const int kMallocHistogramSize = 64; + +typedef std::string MallocExtensionWriter; + +namespace base { +struct MallocRange; +} + +// The default implementations of the following routines do nothing. +// All implementations should be thread-safe; the current one +// (TCMallocImplementation) is. +class PERFTOOLS_DLL_DECL MallocExtension { + public: + virtual ~MallocExtension(); + + // Call this very early in the program execution -- say, in a global + // constructor -- to set up parameters and state needed by all + // instrumented malloc implemenatations. One example: this routine + // sets environemnt variables to tell STL to use libc's malloc() + // instead of doing its own memory management. This is safe to call + // multiple times, as long as each time is before threads start up. + static void Initialize(); + + // See "verify_memory.h" to see what these routines do + virtual bool VerifyAllMemory(); + virtual bool VerifyNewMemory(void* p); + virtual bool VerifyArrayNewMemory(void* p); + virtual bool VerifyMallocMemory(void* p); + virtual bool MallocMemoryStats(int* blocks, size_t* total, + int histogram[kMallocHistogramSize]); + + // Get a human readable description of the current state of the malloc + // data structures. The state is stored as a null-terminated string + // in a prefix of "buffer[0,buffer_length-1]". + // REQUIRES: buffer_length > 0. + virtual void GetStats(char* buffer, int buffer_length); + + // Outputs to "writer" a sample of live objects and the stack traces + // that allocated these objects. The format of the returned output + // is equivalent to the output of the heap profiler and can + // therefore be passed to "pprof". + // NOTE: by default, tcmalloc does not do any heap sampling, and this + // function will always return an empty sample. To get useful + // data from GetHeapSample, you must also set the environment + // variable TCMALLOC_SAMPLE_PARAMETER to a value such as 524288. + virtual void GetHeapSample(MallocExtensionWriter* writer); + + // Outputs to "writer" the stack traces that caused growth in the + // address space size. The format of the returned output is + // equivalent to the output of the heap profiler and can therefore + // be passed to "pprof". (This does not depend on, or require, + // TCMALLOC_SAMPLE_PARAMETER.) + virtual void GetHeapGrowthStacks(MallocExtensionWriter* writer); + + // Invokes func(arg, range) for every controlled memory + // range. *range is filled in with information about the range. + // + // This is a best-effort interface useful only for performance + // analysis. The implementation may not call func at all. + typedef void (RangeFunction)(void*, const base::MallocRange*); + virtual void Ranges(void* arg, RangeFunction func); + + // ------------------------------------------------------------------- + // Control operations for getting and setting malloc implementation + // specific parameters. Some currently useful properties: + // + // generic + // ------- + // "generic.current_allocated_bytes" + // Number of bytes currently allocated by application + // This property is not writable. + // + // "generic.heap_size" + // Number of bytes in the heap == + // current_allocated_bytes + + // fragmentation + + // freed memory regions + // This property is not writable. + // + // tcmalloc + // -------- + // "tcmalloc.max_total_thread_cache_bytes" + // Upper limit on total number of bytes stored across all + // per-thread caches. Default: 16MB. + // + // "tcmalloc.current_total_thread_cache_bytes" + // Number of bytes used across all thread caches. + // This property is not writable. + // + // "tcmalloc.pageheap_free_bytes" + // Number of bytes in free, mapped pages in page heap. These + // bytes can be used to fulfill allocation requests. They + // always count towards virtual memory usage, and unless the + // underlying memory is swapped out by the OS, they also count + // towards physical memory usage. This property is not writable. + // + // "tcmalloc.pageheap_unmapped_bytes" + // Number of bytes in free, unmapped pages in page heap. + // These are bytes that have been released back to the OS, + // possibly by one of the MallocExtension "Release" calls. + // They can be used to fulfill allocation requests, but + // typically incur a page fault. They always count towards + // virtual memory usage, and depending on the OS, typically + // do not count towards physical memory usage. This property + // is not writable. + // ------------------------------------------------------------------- + + // Get the named "property"'s value. Returns true if the property + // is known. Returns false if the property is not a valid property + // name for the current malloc implementation. + // REQUIRES: property != NULL; value != NULL + virtual bool GetNumericProperty(const char* property, size_t* value); + + // Set the named "property"'s value. Returns true if the property + // is known and writable. Returns false if the property is not a + // valid property name for the current malloc implementation, or + // is not writable. + // REQUIRES: property != NULL + virtual bool SetNumericProperty(const char* property, size_t value); + + // Mark the current thread as "idle". This routine may optionally + // be called by threads as a hint to the malloc implementation that + // any thread-specific resources should be released. Note: this may + // be an expensive routine, so it should not be called too often. + // + // Also, if the code that calls this routine will go to sleep for + // a while, it should take care to not allocate anything between + // the call to this routine and the beginning of the sleep. + // + // Most malloc implementations ignore this routine. + virtual void MarkThreadIdle(); + + // Mark the current thread as "busy". This routine should be + // called after MarkThreadIdle() if the thread will now do more + // work. If this method is not called, performance may suffer. + // + // Most malloc implementations ignore this routine. + virtual void MarkThreadBusy(); + + // Try to release num_bytes of free memory back to the operating + // system for reuse. Use this extension with caution -- to get this + // memory back may require faulting pages back in by the OS, and + // that may be slow. (Currently only implemented in tcmalloc.) + virtual void ReleaseToSystem(size_t num_bytes); + + // Same as ReleaseToSystem() but release as much memory as possible. + virtual void ReleaseFreeMemory(); + + // Sets the rate at which we release unused memory to the system. + // Zero means we never release memory back to the system. Increase + // this flag to return memory faster; decrease it to return memory + // slower. Reasonable rates are in the range [0,10]. (Currently + // only implemented in tcmalloc). + virtual void SetMemoryReleaseRate(double rate); + + // Gets the release rate. Returns a value < 0 if unknown. + virtual double GetMemoryReleaseRate(); + + // Returns the estimated number of bytes that will be allocated for + // a request of "size" bytes. This is an estimate: an allocation of + // SIZE bytes may reserve more bytes, but will never reserve less. + // (Currently only implemented in tcmalloc, other implementations + // always return SIZE.) + // This is equivalent to malloc_good_size() in OS X. + virtual size_t GetEstimatedAllocatedSize(size_t size); + + // Returns the actual number N of bytes reserved by tcmalloc for the + // pointer p. The client is allowed to use the range of bytes + // [p, p+N) in any way it wishes (i.e. N is the "usable size" of this + // allocation). This number may be equal to or greater than the number + // of bytes requested when p was allocated. + // p must have been allocated by this malloc implementation, + // must not be an interior pointer -- that is, must be exactly + // the pointer returned to by malloc() et al., not some offset + // from that -- and should not have been freed yet. p may be NULL. + // (Currently only implemented in tcmalloc; other implementations + // will return 0.) + // This is equivalent to malloc_size() in OS X, malloc_usable_size() + // in glibc, and _msize() for windows. + virtual size_t GetAllocatedSize(void* p); + + // The current malloc implementation. Always non-NULL. + static MallocExtension* instance(); + + // Change the malloc implementation. Typically called by the + // malloc implementation during initialization. + static void Register(MallocExtension* implementation); + + // Returns detailed information about malloc's freelists. For each list, + // return a FreeListInfo: + struct FreeListInfo { + size_t min_object_size; + size_t max_object_size; + size_t total_bytes_free; + const char* type; + }; + // Each item in the vector refers to a different freelist. The lists + // are identified by the range of allocations that objects in the + // list can satisfy ([min_object_size, max_object_size]) and the + // type of freelist (see below). The current size of the list is + // returned in total_bytes_free (which count against a processes + // resident and virtual size). + // + // Currently supported types are: + // + // "tcmalloc.page{_unmapped}" - tcmalloc's page heap. An entry for each size + // class in the page heap is returned. Bytes in "page_unmapped" + // are no longer backed by physical memory and do not count against + // the resident size of a process. + // + // "tcmalloc.large{_unmapped}" - tcmalloc's list of objects larger + // than the largest page heap size class. Only one "large" + // entry is returned. There is no upper-bound on the size + // of objects in the large free list; this call returns + // kint64max for max_object_size. Bytes in + // "large_unmapped" are no longer backed by physical memory + // and do not count against the resident size of a process. + // + // "tcmalloc.central" - tcmalloc's central free-list. One entry per + // size-class is returned. Never unmapped. + // + // "debug.free_queue" - free objects queued by the debug allocator + // and not returned to tcmalloc. + // + // "tcmalloc.thread" - tcmalloc's per-thread caches. Never unmapped. + virtual void GetFreeListSizes(std::vector* v); + + protected: + // Get a list of stack traces of sampled allocation points. Returns + // a pointer to a "new[]-ed" result array, and stores the sample + // period in "sample_period". + // + // The state is stored as a sequence of adjacent entries + // in the returned array. Each entry has the following form: + // uintptr_t count; // Number of objects with following trace + // uintptr_t size; // Total size of objects with following trace + // uintptr_t depth; // Number of PC values in stack trace + // void* stack[depth]; // PC values that form the stack trace + // + // The list of entries is terminated by a "count" of 0. + // + // It is the responsibility of the caller to "delete[]" the returned array. + // + // May return NULL to indicate no results. + // + // This is an internal extension. Callers should use the more + // convenient "GetHeapSample(string*)" method defined above. + virtual void** ReadStackTraces(int* sample_period); + + // Like ReadStackTraces(), but returns stack traces that caused growth + // in the address space size. + virtual void** ReadHeapGrowthStackTraces(); +}; + +void TCMallocGetHeapSample(std::string* writer) { + MallocExtension::instance()->GetHeapSample(writer); +} + diff --git a/src/sofa/pbrpc/web_service.cc b/src/sofa/pbrpc/web_service.cc index b939265..cc08b76 100644 --- a/src/sofa/pbrpc/web_service.cc +++ b/src/sofa/pbrpc/web_service.cc @@ -343,10 +343,12 @@ bool WebService::DefaultProfiling(const HTTPRequest& request, Profiling::ProfilingType profiling_type = Profiling::DEFAULT; Profiling::DataType data_type = Profiling::PAGE; + std::string view_prof; + std::string base_prof; + QueryParams::const_iterator it = query_params->find("cpu"); if (it != query_params->end()) { - profiling_type = Profiling::CPU; } else @@ -367,14 +369,38 @@ bool WebService::DefaultProfiling(const HTTPRequest& request, { data_type = Profiling::NEW_GRAPH; } + else if (it->second == "diff") + { + data_type = Profiling::DIFF; + } + else if (it->second == "cleanup") + { + data_type = Profiling::CLEANUP; + } else { data_type = Profiling::PAGE; } } + it = query_params->find("prof"); + if (it != query_params->end()) + { + view_prof = it->second; + } + else + { + view_prof = "default"; + } + it = query_params->find("base"); + if (it != query_params->end()) + { + base_prof = it->second; + } + Profiling* instance = Profiling::Instance(); - return response.content->Append(instance->ProfilingPage(profiling_type, data_type)); + return response.content->Append(instance->ProfilingPage( + profiling_type, data_type, view_prof, base_prof)); } void WebService::PageHeader(std::ostream& out) From 92def49fa207b6d8c3360118f076e35e74a00439 Mon Sep 17 00:00:00 2001 From: zd-double Date: Wed, 30 Nov 2016 22:58:41 +0800 Subject: [PATCH 2/3] Update memory profiling --- src/sofa/pbrpc/profiling.cc | 24 ++++++++++++++++++++++++ src/sofa/pbrpc/profiling.h | 13 ++++++++++++- src/sofa/pbrpc/web_service.cc | 23 ++--------------------- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/sofa/pbrpc/profiling.cc b/src/sofa/pbrpc/profiling.cc index d34c8d7..1983a05 100644 --- a/src/sofa/pbrpc/profiling.cc +++ b/src/sofa/pbrpc/profiling.cc @@ -7,7 +7,9 @@ #include #include #include + #include + #include #include #include @@ -244,6 +246,7 @@ int Profiling::Init() { return -1; } + InitParamMap(); _is_initialized = true; return 0; } @@ -257,6 +260,27 @@ Profiling::~Profiling() } } +void Profiling::InitParamMap() +{ + _param_map["graph"] = GRAPH; + _param_map["newgraph"] = NEW_GRAPH; + _param_map["diff"] = DIFF; + _param_map["cleanup"] = CLEANUP; +} + +Profiling::DataType Profiling::FindDataType(const std::string& data_type) +{ + ParamMap::iterator it = _param_map.find(data_type); + if (it != _param_map.end()) + { + return it->second; + } + else + { + return Profiling::PAGE; + } +} + std::string Profiling::ProfilingPage(ProfilingType profiling_type, DataType data_type, std::string& view_prof, diff --git a/src/sofa/pbrpc/profiling.h b/src/sofa/pbrpc/profiling.h index 2ae0a20..635cee0 100644 --- a/src/sofa/pbrpc/profiling.h +++ b/src/sofa/pbrpc/profiling.h @@ -6,6 +6,8 @@ #define _SOFA_PBRPC_PROFILING_H_ #include +#include + #include #include @@ -31,6 +33,8 @@ class Profiling CLEANUP = 5 }; + typedef std::map ParamMap; + enum Status { OK = 1, @@ -52,17 +56,22 @@ class Profiling int Init(); + DataType FindDataType(const std::string& data_type); + private: Profiling(); ~Profiling(); + void InitParamMap(); + void CpuProfilingFunc(); void MemoryProfilingFunc(); std::string ShowResult(ProfilingType profiling_type, - const std::string& profiling_file, const std::string& profiling_base); + const std::string& profiling_file, + const std::string& profiling_base); static void InitProfiling(); @@ -89,6 +98,8 @@ class Profiling static Profiling* _instance; + ParamMap _param_map; + SOFA_PBRPC_DISALLOW_EVIL_CONSTRUCTORS(Profiling); }; diff --git a/src/sofa/pbrpc/web_service.cc b/src/sofa/pbrpc/web_service.cc index 2b4236e..a19e842 100644 --- a/src/sofa/pbrpc/web_service.cc +++ b/src/sofa/pbrpc/web_service.cc @@ -343,6 +343,7 @@ bool WebService::DefaultProfiling(const HTTPRequest& request, Profiling::ProfilingType profiling_type = Profiling::DEFAULT; Profiling::DataType data_type = Profiling::PAGE; + Profiling* instance = Profiling::Instance(); std::string view_prof; std::string base_prof; @@ -362,26 +363,7 @@ bool WebService::DefaultProfiling(const HTTPRequest& request, } if (it != query_params->end()) { - if (it->second == "graph") - { - data_type = Profiling::GRAPH; - } - else if (it->second == "newgraph") - { - data_type = Profiling::NEW_GRAPH; - } - else if (it->second == "diff") - { - data_type = Profiling::DIFF; - } - else if (it->second == "cleanup") - { - data_type = Profiling::CLEANUP; - } - else - { - data_type = Profiling::PAGE; - } + data_type = instance->FindDataType(it->second); } it = query_params->find("prof"); @@ -399,7 +381,6 @@ bool WebService::DefaultProfiling(const HTTPRequest& request, base_prof = it->second; } - Profiling* instance = Profiling::Instance(); return response.content->Append(instance->ProfilingPage( profiling_type, data_type, view_prof, base_prof)); } From 69afa4f7667062166cf38e5a691bf0397ec22dea Mon Sep 17 00:00:00 2001 From: zd-double Date: Fri, 9 Dec 2016 00:53:46 +0800 Subject: [PATCH 3/3] Update memory profiling --- src/sofa/pbrpc/profiling.cc | 289 +++++++++++++++++----------------- src/sofa/pbrpc/profiling.h | 36 +++-- src/sofa/pbrpc/web_service.cc | 6 +- 3 files changed, 166 insertions(+), 165 deletions(-) diff --git a/src/sofa/pbrpc/profiling.cc b/src/sofa/pbrpc/profiling.cc index 1983a05..11705e6 100644 --- a/src/sofa/pbrpc/profiling.cc +++ b/src/sofa/pbrpc/profiling.cc @@ -148,68 +148,6 @@ static std::string Readlink(const char* symbol_link) return std::string(buf); } -void Profiling::CpuProfilingFunc() -{ - if (!IsFileExist(_dir.path + CPU_PROFILING_PATH)) - { - bool ret = Mkdir(_dir.path + CPU_PROFILING_PATH); - if (ret == false) - { - return; - } - } - struct timeval tval; - gettimeofday(&tval, NULL); - std::string path = _dir.path - + CPU_PROFILING_PATH + "tmp." - + StringUtils::uint64_to_string(tval.tv_sec) - + ".prof"; - ProfilerStart(path.c_str()); - sleep(SOFA_PBRPC_PROFILING_SAMPLE_TIME); - ProfilerStop(); - _is_cpu_profiling = false; -} - -void Profiling::MemoryProfilingFunc() -{ - if (!IsFileExist(_dir.path + MEMORY_PROFILING_PATH)) - { - bool ret = Mkdir(_dir.path + MEMORY_PROFILING_PATH); - if (ret == false) - { - return; - } - } - struct timeval tval; - gettimeofday(&tval, NULL); - std::string path = _dir.path - + MEMORY_PROFILING_PATH + "tmp." - + StringUtils::uint64_to_string(tval.tv_sec) - + ".heap"; - - std::string writer; - TCMallocGetHeapSample(&writer); - if (!WriteFile(path, writer.c_str(), writer.size())) - { -#if defined( LOG ) - LOG(ERROR) << "WriteFile(): write file {" << path << "} failed"; -#else - SLOG(ERROR, "WriteFile(): write file {%s} failed", path.c_str()); -#endif - return; - } - _is_mem_profiling = false; -} - -Profiling::Profiling() -: _is_cpu_profiling(false) - , _is_mem_profiling(false) - , _is_initialized(false) -{ - _profiling_thread_group.reset(new ThreadGroupImpl( - 1, "sofa_pbrpc_profiling_thread_group")); -} - int Profiling::Init() { if (_is_initialized) @@ -246,32 +184,21 @@ int Profiling::Init() { return -1; } - InitParamMap(); + InitOperationMap(); _is_initialized = true; return 0; } -Profiling::~Profiling() -{ - if (_is_initialized) - { - _profiling_thread_group->stop(); - _profiling_thread_group.reset(); - } -} - -void Profiling::InitParamMap() +Profiling* Profiling::Instance() { - _param_map["graph"] = GRAPH; - _param_map["newgraph"] = NEW_GRAPH; - _param_map["diff"] = DIFF; - _param_map["cleanup"] = CLEANUP; + pthread_once(&_init_once, &Profiling::InitProfiling); + return _instance; } -Profiling::DataType Profiling::FindDataType(const std::string& data_type) +Profiling::OperationType Profiling::FindOperationType(const std::string& operation_type) { - ParamMap::iterator it = _param_map.find(data_type); - if (it != _param_map.end()) + OperationMap::iterator it = _operation_map.find(operation_type); + if (it != _operation_map.end()) { return it->second; } @@ -282,7 +209,7 @@ Profiling::DataType Profiling::FindDataType(const std::string& data_type) } std::string Profiling::ProfilingPage(ProfilingType profiling_type, - DataType data_type, + OperationType operation_type, std::string& view_prof, std::string& base_prof) { @@ -301,13 +228,13 @@ std::string Profiling::ProfilingPage(ProfilingType profiling_type, switch (profiling_type) { case CPU: - if (data_type == GRAPH) + if (operation_type == GRAPH) { oss.str(""); oss.clear(); std::string cmd = "perl " + _dir.path + "/rpc_profiling/pprof.perl --dot " - + _dir.path + "/" + _dir.name + " " + _dir.path - + CPU_PROFILING_PATH + view_prof; + + _dir.path + "/" + _dir.name + " " + _dir.path + + CPU_PROFILING_PATH + view_prof; if (!base_prof.empty()) { cmd.append(" --base " + _dir.path + CPU_PROFILING_PATH + base_prof); @@ -316,7 +243,7 @@ std::string Profiling::ProfilingPage(ProfilingType profiling_type, oss << dot; return oss.str(); } - else if (data_type == CLEANUP) + else if (operation_type == CLEANUP) { std::set profiling_set; ListFile(_dir.path + CPU_PROFILING_PATH, profiling_set); @@ -327,13 +254,13 @@ std::string Profiling::ProfilingPage(ProfilingType profiling_type, } oss << ShowResult(profiling_type, view_prof, base_prof); } - else if (data_type == DIFF) + else if (operation_type == DIFF) { oss << ShowResult(profiling_type, view_prof, base_prof); } else { - Status ret = DoCpuProfiling(data_type, view_prof); + Status ret = DoCpuProfiling(operation_type, view_prof); if (ret == DISABLE) { oss << "

To enable profiling, please add compile and link options when compiling binary:

"; @@ -366,13 +293,13 @@ std::string Profiling::ProfilingPage(ProfilingType profiling_type, } break; case MEMORY: - if (data_type == GRAPH) + if (operation_type == GRAPH) { oss.str(""); oss.clear(); std::string cmd = "perl " + _dir.path + "/rpc_profiling/pprof.perl --dot " - + _dir.path + "/" + _dir.name + " " + _dir.path - + MEMORY_PROFILING_PATH + view_prof; + + _dir.path + "/" + _dir.name + " " + _dir.path + + MEMORY_PROFILING_PATH + view_prof; if (!base_prof.empty()) { cmd.append(" --base " + _dir.path + MEMORY_PROFILING_PATH + base_prof); @@ -381,7 +308,7 @@ std::string Profiling::ProfilingPage(ProfilingType profiling_type, oss << dot; return oss.str(); } - else if (data_type == CLEANUP) + else if (operation_type == CLEANUP) { std::set profiling_set; ListFile(_dir.path + MEMORY_PROFILING_PATH, profiling_set); @@ -392,13 +319,13 @@ std::string Profiling::ProfilingPage(ProfilingType profiling_type, } oss << ShowResult(profiling_type, view_prof, base_prof); } - else if (data_type == DIFF) + else if (operation_type == DIFF) { oss << ShowResult(profiling_type, view_prof, base_prof); } else { - Status ret = DoMemoryProfiling(data_type, view_prof); + Status ret = DoMemoryProfiling(operation_type, view_prof); if (ret == DISABLE) { oss << "

To enable memory profiling, please add compile and link options when compiling binary:

"; @@ -442,7 +369,8 @@ std::string Profiling::ProfilingPage(ProfilingType profiling_type, return oss.str(); } -Profiling::Status Profiling::DoCpuProfiling(DataType data_type, std::string& profiling_file) +Profiling::Status Profiling::DoCpuProfiling(OperationType operation_type, + std::string& profiling_file) { if (ProfilerStart == NULL) { @@ -457,7 +385,7 @@ Profiling::Status Profiling::DoCpuProfiling(DataType data_type, std::string& pro std::set profiling_set; ListFile(_dir.path + CPU_PROFILING_PATH, profiling_set); - if (profiling_file == "default" && !profiling_set.empty() && data_type != NEW_GRAPH) + if (profiling_file == "default" && !profiling_set.empty() && operation_type != NEW_GRAPH) { profiling_file = *(profiling_set.rbegin()); return FINISHED; @@ -474,6 +402,127 @@ Profiling::Status Profiling::DoCpuProfiling(DataType data_type, std::string& pro return OK; } +Profiling::Status Profiling::DoMemoryProfiling(OperationType operation_type, + std::string& profiling_file) +{ + if (TCMallocGetHeapSample == NULL) + { + return DISABLE; + } + + if (_is_mem_profiling == true) + { + return PROFILING; + } + + std::set profiling_set; + ListFile(_dir.path + MEMORY_PROFILING_PATH, profiling_set); + + if (profiling_file == "default" && !profiling_set.empty() && operation_type != NEW_GRAPH) + { + profiling_file = *(profiling_set.rbegin()); + return FINISHED; + } + if (IsFileExist(_dir.path + MEMORY_PROFILING_PATH + profiling_file)) + { + return FINISHED; + } + _is_mem_profiling = true; + google::protobuf::Closure* done = + sofa::pbrpc::NewClosure(Profiling::Instance(), + &Profiling::MemoryProfilingFunc); + _profiling_thread_group->post(done); + return OK; +} + +Profiling::Profiling() + : _is_cpu_profiling(false) + , _is_mem_profiling(false) + , _is_initialized(false) +{ + _profiling_thread_group.reset(new ThreadGroupImpl( + 1, "sofa_pbrpc_profiling_thread_group")); +} + +Profiling::~Profiling() +{ + if (_is_initialized) + { + _profiling_thread_group->stop(); + _profiling_thread_group.reset(); + } +} + +void Profiling::InitProfiling() +{ + _instance = new Profiling(); + ::atexit(DestroyProfiling); +} + +void Profiling::DestroyProfiling() +{ + delete _instance; + _instance = NULL; +} + +void Profiling::InitOperationMap() +{ + _operation_map["graph"] = GRAPH; + _operation_map["newgraph"] = NEW_GRAPH; + _operation_map["diff"] = DIFF; + _operation_map["cleanup"] = CLEANUP; +} + +void Profiling::CpuProfilingFunc() +{ + if (!IsFileExist(_dir.path + CPU_PROFILING_PATH)) + { + if (!Mkdir(_dir.path + CPU_PROFILING_PATH)) + { + return; + } + } + struct timeval tval; + gettimeofday(&tval, NULL); + std::string path = _dir.path + + CPU_PROFILING_PATH + "tmp." + + StringUtils::uint64_to_string(tval.tv_sec) + + ".prof"; + ProfilerStart(path.c_str()); + sleep(SOFA_PBRPC_PROFILING_SAMPLE_TIME); + ProfilerStop(); + _is_cpu_profiling = false; +} + +void Profiling::MemoryProfilingFunc() +{ + if (!IsFileExist(_dir.path + MEMORY_PROFILING_PATH)) + { + if (!Mkdir(_dir.path + MEMORY_PROFILING_PATH)) + { + return; + } + } + struct timeval tval; + gettimeofday(&tval, NULL); + std::string path = _dir.path + + MEMORY_PROFILING_PATH + "tmp." + + StringUtils::uint64_to_string(tval.tv_sec) + + ".heap"; + std::string writer; + TCMallocGetHeapSample(&writer); + if (!WriteFile(path, writer.c_str(), writer.size())) + { +#if defined( LOG ) + LOG(ERROR) << "WriteFile(): write file {" << path << "} failed"; +#else + SLOG(ERROR, "WriteFile(): write file {%s} failed", path.c_str()); +#endif + return; + } + _is_mem_profiling = false; +} + std::string Profiling::ShowResult(ProfilingType profiling_type, const std::string& view_prof, const std::string& base_prof) @@ -586,55 +635,5 @@ std::string Profiling::ShowResult(ProfilingType profiling_type, return oss.str(); } -Profiling::Status Profiling::DoMemoryProfiling(DataType data_type, std::string& profiling_file) -{ - if (TCMallocGetHeapSample == NULL) - { - return DISABLE; - } - - if (_is_mem_profiling == true) - { - return PROFILING; - } - - std::set profiling_set; - ListFile(_dir.path + MEMORY_PROFILING_PATH, profiling_set); - - if (profiling_file == "default" && !profiling_set.empty() && data_type != NEW_GRAPH) - { - profiling_file = *(profiling_set.rbegin()); - return FINISHED; - } - if (IsFileExist(_dir.path + MEMORY_PROFILING_PATH + profiling_file)) - { - return FINISHED; - } - _is_mem_profiling = true; - google::protobuf::Closure* done = - sofa::pbrpc::NewClosure(Profiling::Instance(), - &Profiling::MemoryProfilingFunc); - _profiling_thread_group->post(done); - return OK; -} - -Profiling* Profiling::Instance() -{ - pthread_once(&_init_once, &Profiling::InitProfiling); - return _instance; -} - -void Profiling::InitProfiling() -{ - _instance = new Profiling(); - ::atexit(DestroyProfiling); -} - -void Profiling::DestroyProfiling() -{ - delete _instance; - _instance = NULL; -} - } // namespace pbrpc } // namespace sofa diff --git a/src/sofa/pbrpc/profiling.h b/src/sofa/pbrpc/profiling.h index 635cee0..1d521f6 100644 --- a/src/sofa/pbrpc/profiling.h +++ b/src/sofa/pbrpc/profiling.h @@ -24,7 +24,7 @@ class Profiling MEMORY = 4, }; - enum DataType + enum OperationType { PAGE = 1, GRAPH = 2, @@ -33,7 +33,7 @@ class Profiling CLEANUP = 5 }; - typedef std::map ParamMap; + typedef std::map OperationMap; enum Status { @@ -43,27 +43,33 @@ class Profiling FINISHED = 4 }; + int Init(); + + static Profiling* Instance(); + + OperationType FindOperationType(const std::string& operation_type); + std::string ProfilingPage(ProfilingType profiling_type, - DataType data_type, + OperationType operation_type, std::string& profiling_file, std::string& profiling_base); - Status DoCpuProfiling(DataType data_type, std::string& profiling_file); + Status DoCpuProfiling(OperationType operation_type, + std::string& profiling_file); - Status DoMemoryProfiling(DataType data_type, std::string& profiling_file); - - static Profiling* Instance(); - - int Init(); - - DataType FindDataType(const std::string& data_type); + Status DoMemoryProfiling(OperationType operation_type, + std::string& profiling_file); private: Profiling(); ~Profiling(); - void InitParamMap(); + static void InitProfiling(); + + static void DestroyProfiling(); + + void InitOperationMap(); void CpuProfilingFunc(); @@ -73,10 +79,6 @@ class Profiling const std::string& profiling_file, const std::string& profiling_base); - static void InitProfiling(); - - static void DestroyProfiling(); - struct EXEDir { std::string path; @@ -98,7 +100,7 @@ class Profiling static Profiling* _instance; - ParamMap _param_map; + OperationMap _operation_map; SOFA_PBRPC_DISALLOW_EVIL_CONSTRUCTORS(Profiling); }; diff --git a/src/sofa/pbrpc/web_service.cc b/src/sofa/pbrpc/web_service.cc index a19e842..dc6e02f 100644 --- a/src/sofa/pbrpc/web_service.cc +++ b/src/sofa/pbrpc/web_service.cc @@ -342,7 +342,7 @@ bool WebService::DefaultProfiling(const HTTPRequest& request, QueryParams* query_params = request.query_params; Profiling::ProfilingType profiling_type = Profiling::DEFAULT; - Profiling::DataType data_type = Profiling::PAGE; + Profiling::OperationType operation_type = Profiling::PAGE; Profiling* instance = Profiling::Instance(); std::string view_prof; @@ -363,7 +363,7 @@ bool WebService::DefaultProfiling(const HTTPRequest& request, } if (it != query_params->end()) { - data_type = instance->FindDataType(it->second); + operation_type = instance->FindOperationType(it->second); } it = query_params->find("prof"); @@ -382,7 +382,7 @@ bool WebService::DefaultProfiling(const HTTPRequest& request, } return response.content->Append(instance->ProfilingPage( - profiling_type, data_type, view_prof, base_prof)); + profiling_type, operation_type, view_prof, base_prof)); } void WebService::PageHeader(std::ostream& out)