[PATCH] Extend prifiling tool to support Vsize and Rss memory usage profile per call

Shuang He shuang.he at intel.com
Wed Feb 27 16:45:33 PST 2013


So, any more thoughts on this?

Thanks
     --Shuang

On 2013/2/18 10:09, Shuang He wrote:
> Add one new option -pmem for retrace tool to track Visze and Rss usage during every call
>
> Signed-off-by: Shuang He <shuang.he at intel.com>
> ---
>   CMakeLists.txt             |    4 +++
>   common/os_memory.hpp       |   67 ++++++++++++++++++++++++++++++++++++++++++
>   common/trace_profiler.cpp  |   70 +++++++++++++++++++++++++++++++++++++++++---
>   common/trace_profiler.hpp  |   26 ++++++++++++++--
>   retrace/CMakeLists.txt     |    6 ++++
>   retrace/glretrace_main.cpp |   46 +++++++++++++++++++++++++++--
>   retrace/retrace.hpp        |    3 ++
>   retrace/retrace_main.cpp   |   15 +++++++++-
>   8 files changed, 228 insertions(+), 9 deletions(-)
>   create mode 100644 common/os_memory.hpp
>
> diff --git a/CMakeLists.txt b/CMakeLists.txt
> index 91f1b87..90bfc87 100644
> --- a/CMakeLists.txt
> +++ b/CMakeLists.txt
> @@ -191,6 +191,10 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
>           ERROR_QUIET
>           OUTPUT_STRIP_TRAILING_WHITESPACE
>       )
> +    CHECK_INCLUDE_FILES(proc/readproc.h READPROC_H_FOUND)
> +    if (READPROC_H_FOUND)
> +        add_definitions (-DHAVE_READPROC_H)
> +    endif ()
>   endif()
>   
>   if (WIN32 OR APPLE)
> diff --git a/common/os_memory.hpp b/common/os_memory.hpp
> new file mode 100644
> index 0000000..e0c5630
> --- /dev/null
> +++ b/common/os_memory.hpp
> @@ -0,0 +1,67 @@
> +/**************************************************************************
> + *
> + * Copyright (C) 2013 Intel Corporation. All rights reversed.
> + * Author: Shuang He <shuang.he at intel.com>
> + * All Rights Reserved.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + *
> + **************************************************************************/
> +
> +/*
> + * Simple OS time measurement abstraction.
> + */
> +
> +#ifndef _OS_MEMORY_HPP_
> +#define _OS_MEMORY_HPP_
> +
> +#ifdef HAVE_READPROC_H
> +#include <proc/readproc.h>
> +
> +namespace os {
> +    inline long long
> +    getVsize(void) {
> +        proc_t proc;
> +	look_up_our_self(&proc);
> +        return proc.vsize;
> +    }
> +
> +    inline long long
> +    getRss(void) {
> +        proc_t proc;
> +	look_up_our_self(&proc);
> +        return proc.rss;
> +    }
> +} /* namespace os */
> +
> +#else
> +namespace os {
> +    inline long long
> +    getVsize(void) {
> +        return 0;
> +    }
> +
> +    inline long long
> +    getRss(void) {
> +        return 0;
> +    }
> +} /* namespace os */
> +#endif
> +
> +#endif /* _OS_MEMORY_HPP_ */
> diff --git a/common/trace_profiler.cpp b/common/trace_profiler.cpp
> index 0f90ee2..d4d4260 100644
> --- a/common/trace_profiler.cpp
> +++ b/common/trace_profiler.cpp
> @@ -1,6 +1,7 @@
>   /**************************************************************************
>    *
>    * Copyright 2012 VMware, Inc.
> + * Copyright 2013 Intel, Inc.
>    * All Rights Reserved.
>    *
>    * Permission is hereby granted, free of charge, to any person obtaining a copy
> @@ -34,9 +35,12 @@ Profiler::Profiler()
>       : baseGpuTime(0),
>         baseCpuTime(0),
>         minCpuTime(1000),
> +      baseVsizeUsage(0),
> +      baseRssUsage(0),
>         cpuTimes(false),
>         gpuTimes(true),
> -      pixelsDrawn(false)
> +      pixelsDrawn(false),
> +      memoryUsage(false)
>   {
>   }
>   
> @@ -44,13 +48,14 @@ Profiler::~Profiler()
>   {
>   }
>   
> -void Profiler::setup(bool cpuTimes_, bool gpuTimes_, bool pixelsDrawn_)
> +void Profiler::setup(bool cpuTimes_, bool gpuTimes_, bool pixelsDrawn_, bool memoryUsage_)
>   {
>       cpuTimes = cpuTimes_;
>       gpuTimes = gpuTimes_;
>       pixelsDrawn = pixelsDrawn_;
> +    memoryUsage = memoryUsage_;
>   
> -    std::cout << "# call no gpu_start gpu_dura cpu_start cpu_dura pixels program name" << std::endl;
> +    std::cout << "# call no gpu_start gpu_dura cpu_start cpu_dura vsize_start vsize_dura rss_start rss_dura pixels program name" << std::endl;
>   }
>   
>   int64_t Profiler::getBaseCpuTime()
> @@ -63,6 +68,16 @@ int64_t Profiler::getBaseGpuTime()
>       return baseGpuTime;
>   }
>   
> +int64_t Profiler::getBaseVsizeUsage()
> +{
> +    return baseVsizeUsage;
> +}
> +
> +int64_t Profiler::getBaseRssUsage()
> +{
> +    return baseRssUsage;
> +}
> +
>   void Profiler::setBaseCpuTime(int64_t cpuStart)
>   {
>       baseCpuTime = cpuStart;
> @@ -73,6 +88,16 @@ void Profiler::setBaseGpuTime(int64_t gpuStart)
>       baseGpuTime = gpuStart;
>   }
>   
> +void Profiler::setBaseVsizeUsage(int64_t vsizeStart)
> +{
> +    baseVsizeUsage = vsizeStart;
> +}
> +
> +void Profiler::setBaseRssUsage(int64_t rssStart)
> +{
> +    baseRssUsage = rssStart;
> +}
> +
>   bool Profiler::hasBaseTimes()
>   {
>       return baseCpuTime != 0 || baseGpuTime != 0;
> @@ -83,7 +108,9 @@ void Profiler::addCall(unsigned no,
>                          unsigned program,
>                          int64_t pixels,
>                          int64_t gpuStart, int64_t gpuDuration,
> -                       int64_t cpuStart, int64_t cpuDuration)
> +                       int64_t cpuStart, int64_t cpuDuration,
> +		       int64_t vsizeStart, int64_t vsizeDuration,
> +		       int64_t rssStart, int64_t rssDuration)
>   {
>       if (gpuTimes && gpuStart) {
>           gpuStart -= baseGpuTime;
> @@ -109,12 +136,23 @@ void Profiler::addCall(unsigned no,
>           pixels = 0;
>       }
>   
> +    if (!memoryUsage || !vsizeStart || !rssStart) {
> +        vsizeStart = 0;
> +	vsizeDuration = 0;
> +	rssStart = 0;
> +	rssDuration = 0;
> +    }
> +
>       std::cout << "call"
>                 << " " << no
>                 << " " << gpuStart
>                 << " " << gpuDuration
>                 << " " << cpuStart
>                 << " " << cpuDuration
> +	      << " " << vsizeStart
> +	      << " " << vsizeDuration
> +	      << " " << rssStart
> +	      << " " << rssDuration
>                 << " " << pixels
>                 << " " << program
>                 << " " << name
> @@ -132,6 +170,8 @@ void Profiler::parseLine(const char* in, Profile* profile)
>       std::string type;
>       static int64_t lastGpuTime;
>       static int64_t lastCpuTime;
> +    static int64_t lastVsizeUsage;
> +    static int64_t lastRssUsage;
>   
>       if (in[0] == '#' || strlen(in) < 4)
>           return;
> @@ -139,6 +179,8 @@ void Profiler::parseLine(const char* in, Profile* profile)
>       if (profile->programs.size() == 0 && profile->calls.size() == 0 && profile->frames.size() == 0) {
>           lastGpuTime = 0;
>           lastCpuTime = 0;
> +	lastVsizeUsage = 0;
> +	lastRssUsage = 0;
>       }
>   
>       line >> type;
> @@ -151,6 +193,10 @@ void Profiler::parseLine(const char* in, Profile* profile)
>                >> call.gpuDuration
>                >> call.cpuStart
>                >> call.cpuDuration
> +	     >> call.vsizeStart
> +	     >> call.vsizeDuration
> +	     >> call.rssStart
> +	     >> call.rssDuration
>                >> call.pixels
>                >> call.program
>                >> call.name;
> @@ -163,6 +209,14 @@ void Profiler::parseLine(const char* in, Profile* profile)
>               lastCpuTime = call.cpuStart + call.cpuDuration;
>           }
>   
> +	if (lastVsizeUsage < call.vsizeStart + call.vsizeDuration) {
> +            lastVsizeUsage = call.vsizeStart + call.vsizeDuration;
> +	}
> +
> +	if (lastRssUsage < call.rssStart + call.rssDuration) {
> +            lastRssUsage = call.rssStart + call.rssDuration;
> +	}
> +
>           profile->calls.push_back(call);
>   
>           if (call.pixels >= 0) {
> @@ -174,6 +228,8 @@ void Profiler::parseLine(const char* in, Profile* profile)
>               program.cpuTotal += call.cpuDuration;
>               program.gpuTotal += call.gpuDuration;
>               program.pixelTotal += call.pixels;
> +	    program.vsizeTotal += call.vsizeDuration;
> +	    program.rssTotal += call.rssDuration;
>               program.calls.push_back(profile->calls.size() - 1);
>           }
>       } else if (type.compare("frame_end") == 0) {
> @@ -183,15 +239,21 @@ void Profiler::parseLine(const char* in, Profile* profile)
>           if (frame.no == 0) {
>               frame.gpuStart = 0;
>               frame.cpuStart = 0;
> +	    frame.vsizeStart = 0;
> +	    frame.rssStart = 0;
>               frame.calls.begin = 0;
>           } else {
>               frame.gpuStart = profile->frames.back().gpuStart + profile->frames.back().gpuDuration;
>               frame.cpuStart = profile->frames.back().cpuStart + profile->frames.back().cpuDuration;
> +	    frame.vsizeStart = profile->frames.back().vsizeStart + profile->frames.back().vsizeDuration;
> +	    frame.rssStart = profile->frames.back().rssStart + profile->frames.back().rssDuration;
>               frame.calls.begin = profile->frames.back().calls.end + 1;
>           }
>   
>           frame.gpuDuration = lastGpuTime - frame.gpuStart;
>           frame.cpuDuration = lastCpuTime - frame.cpuStart;
> +	frame.vsizeDuration = lastVsizeUsage - frame.vsizeStart;
> +	frame.rssDuration = lastRssUsage - frame.rssStart;
>           frame.calls.end = profile->calls.size() - 1;
>   
>           profile->frames.push_back(frame);
> diff --git a/common/trace_profiler.hpp b/common/trace_profiler.hpp
> index d833242..b0b3bd5 100644
> --- a/common/trace_profiler.hpp
> +++ b/common/trace_profiler.hpp
> @@ -1,6 +1,7 @@
>   /**************************************************************************
>    *
>    * Copyright 2012 VMware, Inc.
> + * Copyright 2013 Intel, Inc.
>    * All Rights Reserved.
>    *
>    * Permission is hereby granted, free of charge, to any person obtaining a copy
> @@ -45,6 +46,11 @@ struct Profile {
>           int64_t cpuStart;
>           int64_t cpuDuration;
>   
> +	int64_t vsizeStart;
> +	int64_t vsizeDuration;
> +	int64_t rssStart;
> +	int64_t rssDuration;
> +
>           int64_t pixels;
>   
>           std::string name;
> @@ -59,6 +65,11 @@ struct Profile {
>           int64_t cpuStart;
>           int64_t cpuDuration;
>   
> +	int64_t vsizeStart;
> +	int64_t vsizeDuration;
> +	int64_t rssStart;
> +	int64_t rssDuration;
> +
>           /* Indices to profile->calls array */
>           struct {
>               unsigned begin;
> @@ -72,6 +83,8 @@ struct Profile {
>           uint64_t gpuTotal;
>           uint64_t cpuTotal;
>           uint64_t pixelTotal;
> +	int64_t vsizeTotal;
> +	int64_t rssTotal;
>   
>           /* Indices to profile->calls array */
>           std::vector<unsigned> calls;
> @@ -88,14 +101,16 @@ public:
>       Profiler();
>       ~Profiler();
>   
> -    void setup(bool cpuTimes_, bool gpuTimes_, bool pixelsDrawn_);
> +    void setup(bool cpuTimes_, bool gpuTimes_, bool pixelsDrawn_, bool memoryUsage_);
>   
>       void addCall(unsigned no,
>                    const char* name,
>                    unsigned program,
>                    int64_t pixels,
>                    int64_t gpuStart, int64_t gpuDuration,
> -                 int64_t cpuStart, int64_t cpuDuration);
> +                 int64_t cpuStart, int64_t cpuDuration,
> +		 int64_t vsizeStart, int64_t vsizeDuration,
> +		 int64_t rssStart, int64_t rssDuration);
>   
>       void addFrameEnd();
>   
> @@ -103,9 +118,13 @@ public:
>   
>       void setBaseCpuTime(int64_t cpuStart);
>       void setBaseGpuTime(int64_t gpuStart);
> +    void setBaseVsizeUsage(int64_t vsizeStart);
> +    void setBaseRssUsage(int64_t rssStart);
>   
>       int64_t getBaseCpuTime();
>       int64_t getBaseGpuTime();
> +    int64_t getBaseVsizeUsage();
> +    int64_t getBaseRssUsage();
>   
>       static void parseLine(const char* line, Profile* profile);
>   
> @@ -113,10 +132,13 @@ private:
>       int64_t baseGpuTime;
>       int64_t baseCpuTime;
>       int64_t minCpuTime;
> +    int64_t baseVsizeUsage;
> +    int64_t baseRssUsage;
>   
>       bool cpuTimes;
>       bool gpuTimes;
>       bool pixelsDrawn;
> +    bool memoryUsage;
>   };
>   }
>   
> diff --git a/retrace/CMakeLists.txt b/retrace/CMakeLists.txt
> index b271727..9ea1ae9 100644
> --- a/retrace/CMakeLists.txt
> +++ b/retrace/CMakeLists.txt
> @@ -102,6 +102,9 @@ if (WIN32 OR APPLE OR X11_FOUND)
>   
>           if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
>               target_link_libraries (glretrace rt)
> +            if (READPROC_H_FOUND)
> +                target_link_libraries (glretrace proc)
> +            endif ()
>           endif ()
>   
>       endif ()
> @@ -127,6 +130,9 @@ if (ENABLE_EGL AND X11_FOUND AND NOT WIN32 AND NOT APPLE)
>   
>       if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
>           target_link_libraries (eglretrace rt)
> +        if (READPROC_H_FOUND)
> +            target_link_libraries (eglretrace proc)
> +        endif ()
>       endif ()
>   
>       install (TARGETS eglretrace RUNTIME DESTINATION bin)
> diff --git a/retrace/glretrace_main.cpp b/retrace/glretrace_main.cpp
> index d0298fc..7d0b7c9 100755
> --- a/retrace/glretrace_main.cpp
> +++ b/retrace/glretrace_main.cpp
> @@ -1,6 +1,8 @@
>   /**************************************************************************
>    *
>    * Copyright 2011 Jose Fonseca
> + * Copyright (C) 2013 Intel Corporation. All rights reversed.
> + * Author: Shuang He <shuang.he at intel.com>
>    * All Rights Reserved.
>    *
>    * Permission is hereby granted, free of charge, to any person obtaining a copy
> @@ -31,6 +33,7 @@
>   #include "glstate.hpp"
>   #include "glretrace.hpp"
>   #include "os_time.hpp"
> +#include "os_memory.hpp"
>   
>   /* Synchronous debug output may reduce performance however,
>    * without it the callNo in the callback may be inaccurate
> @@ -59,6 +62,10 @@ struct CallQuery
>       const trace::FunctionSig *sig;
>       int64_t cpuStart;
>       int64_t cpuEnd;
> +    int64_t vsizeStart;
> +    int64_t vsizeEnd;
> +    int64_t rssStart;
> +    int64_t rssEnd;
>   };
>   
>   static bool supportsElapsed = true;
> @@ -137,10 +144,20 @@ getTimeFrequency(void) {
>       }
>   }
>   
> +static inline void
> +getCurrentVsize(int64_t& vsize) {
> +    vsize = os::getVsize();
> +}
> +
> +static inline void
> +getCurrentRss(int64_t& rss) {
> +    rss = os::getRss();
> +}
> +
>   static void
>   completeCallQuery(CallQuery& query) {
>       /* Get call start and duration */
> -    int64_t gpuStart = 0, gpuDuration = 0, cpuDuration = 0, pixels = 0;
> +    int64_t gpuStart = 0, gpuDuration = 0, cpuDuration = 0, pixels = 0, vsizeDuration = 0, rssDuration = 0;
>   
>       if (query.isDraw) {
>           if (retrace::profilingGpuTimes) {
> @@ -163,10 +180,15 @@ completeCallQuery(CallQuery& query) {
>           cpuDuration = query.cpuEnd - query.cpuStart;
>       }
>   
> +    if (retrace::profilingMemoryUsage) {
> +        vsizeDuration = query.vsizeEnd - query.vsizeStart;
> +        rssDuration = query.rssEnd - query.rssStart;
> +    }
> +
>       glDeleteQueries(NUM_QUERIES, query.ids);
>   
>       /* Add call to profile */
> -    retrace::profiler.addCall(query.call, query.sig->name, query.program, pixels, gpuStart, gpuDuration, query.cpuStart, cpuDuration);
> +    retrace::profiler.addCall(query.call, query.sig->name, query.program, pixels, gpuStart, gpuDuration, query.cpuStart, cpuDuration, query.vsizeStart, vsizeDuration, query.rssStart, rssDuration);
>   }
>   
>   void
> @@ -213,6 +235,12 @@ beginProfile(trace::Call &call, bool isDraw) {
>           CallQuery& query = callQueries.back();
>           query.cpuStart = getCurrentTime();
>       }
> +
> +    if (retrace::profilingMemoryUsage) {
> +	CallQuery& query = callQueries.back();
> +        query.vsizeStart = os::getVsize();
> +        query.rssStart = os::getRss();
> +    }
>   }
>   
>   void
> @@ -234,6 +262,12 @@ endProfile(trace::Call &call, bool isDraw) {
>               glEndQuery(GL_SAMPLES_PASSED);
>           }
>       }
> +
> +    if (retrace::profilingMemoryUsage) {
> +        CallQuery& query = callQueries.back();
> +	query.vsizeEnd = os::getVsize();
> +	query.rssEnd = os::getRss();
> +    }
>   }
>   
>   void
> @@ -287,6 +321,14 @@ initContext() {
>               retrace::profiler.setBaseGpuTime(currentTime);
>           }
>       }
> +
> +    if (retrace::profilingMemoryUsage) {
> +        GLint64 currentVsize, currentRss;
> +	getCurrentVsize(currentVsize);
> +	retrace::profiler.setBaseVsizeUsage(currentVsize);
> +	getCurrentRss(currentRss);
> +	retrace::profiler.setBaseRssUsage(currentRss);
> +    }
>   }
>   
>   void
> diff --git a/retrace/retrace.hpp b/retrace/retrace.hpp
> index 7c8dcd5..14317cf 100644
> --- a/retrace/retrace.hpp
> +++ b/retrace/retrace.hpp
> @@ -1,6 +1,8 @@
>   /**************************************************************************
>    *
>    * Copyright 2011-2012 Jose Fonseca
> + * Copyright (C) 2013 Intel Corporation. All rights reversed.
> + * Author: Shuang He <shuang.he at intel.com>
>    * All Rights Reserved.
>    *
>    * Permission is hereby granted, free of charge, to any person obtaining a copy
> @@ -92,6 +94,7 @@ extern bool profiling;
>   extern bool profilingCpuTimes;
>   extern bool profilingGpuTimes;
>   extern bool profilingPixelsDrawn;
> +extern bool profilingMemoryUsage;
>   
>   /**
>    * State dumping.
> diff --git a/retrace/retrace_main.cpp b/retrace/retrace_main.cpp
> index ca03745..257b253 100644
> --- a/retrace/retrace_main.cpp
> +++ b/retrace/retrace_main.cpp
> @@ -1,6 +1,8 @@
>   /**************************************************************************
>    *
>    * Copyright 2011 Jose Fonseca
> + * Copyright (C) 2013 Intel Corporation. All rights reversed.
> + * Author: Shuang He <shuang.he at intel.com>
>    * All Rights Reserved.
>    *
>    * Permission is hereby granted, free of charge, to any person obtaining a copy
> @@ -72,6 +74,7 @@ bool profiling = false;
>   bool profilingGpuTimes = false;
>   bool profilingCpuTimes = false;
>   bool profilingPixelsDrawn = false;
> +bool profilingMemoryUsage = false;
>   bool useCallNos = true;
>   
>   unsigned frameNo = 0;
> @@ -514,6 +517,7 @@ usage(const char *argv0) {
>           "      --pcpu              cpu profiling (cpu times per call)\n"
>           "      --pgpu              gpu profiling (gpu times per draw call)\n"
>           "      --ppd               pixels drawn profiling (pixels drawn per draw call)\n"
> +	"      --pmem              memory usage profiling (vsize rss per call)\n"
>           "  -c, --compare=PREFIX    compare against snapshots with given PREFIX\n"
>           "  -C, --calls=CALLSET     calls to compare (default is every frame)\n"
>           "      --call-nos[=BOOL]   use call numbers in snapshot filenames\n"
> @@ -536,6 +540,7 @@ enum {
>       PCPU_OPT,
>       PGPU_OPT,
>       PPD_OPT,
> +    PMEM_OPT,
>       SB_OPT,
>   };
>   
> @@ -556,6 +561,7 @@ longOptions[] = {
>       {"pcpu", no_argument, 0, PCPU_OPT},
>       {"pgpu", no_argument, 0, PGPU_OPT},
>       {"ppd", no_argument, 0, PPD_OPT},
> +    {"pmem", no_argument, 0, PMEM_OPT},
>       {"sb", no_argument, 0, SB_OPT},
>       {"snapshot-prefix", required_argument, 0, 's'},
>       {"snapshot", required_argument, 0, 'S'},
> @@ -676,6 +682,13 @@ int main(int argc, char **argv)
>   
>               retrace::profilingPixelsDrawn = true;
>               break;
> +        case PMEM_OPT:
> +            retrace::debug = false;
> +	    retrace::profiling = true;
> +	    retrace::verbosity = -1;
> +
> +	    retrace::profilingMemoryUsage = true;
> +	    break;
>           default:
>               std::cerr << "error: unknown option " << opt << "\n";
>               usage(argv[0]);
> @@ -685,7 +698,7 @@ int main(int argc, char **argv)
>   
>       retrace::setUp();
>       if (retrace::profiling) {
> -        retrace::profiler.setup(retrace::profilingCpuTimes, retrace::profilingGpuTimes, retrace::profilingPixelsDrawn);
> +        retrace::profiler.setup(retrace::profilingCpuTimes, retrace::profilingGpuTimes, retrace::profilingPixelsDrawn, retrace::profilingMemoryUsage);
>       }
>   
>       os::setExceptionCallback(exceptionCallback);



More information about the apitrace mailing list