00001 //# MemoryTrace.h: Memory usage tracing mechanism 00002 //# Copyright (C) 2015 00003 //# Associated Universities, Inc. Washington DC, USA. 00004 //# 00005 //# This library is free software; you can redistribute it and/or modify it 00006 //# under the terms of the GNU Library General Public License as published by 00007 //# the Free Software Foundation; either version 2 of the License, or (at your 00008 //# option) any later version. 00009 //# 00010 //# This library is distributed in the hope that it will be useful, but WITHOUT 00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00012 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00013 //# License for more details. 00014 //# 00015 //# You should have received a copy of the GNU Library General Public License 00016 //# along with this library; if not, write to the Free Software Foundation, 00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 00018 //# 00019 //# Correspondence concerning AIPS++ should be addressed as follows: 00020 //# Internet email: aips2-request@nrao.edu. 00021 //# Postal address: AIPS++ Project Office 00022 //# National Radio Astronomy Observatory 00023 //# 520 Edgemont Road 00024 //# Charlottesville, VA 22903-2475 USA 00025 //# 00026 //# $Id: Block.h 21120 2011-09-01 13:51:56Z gervandiepen $ 00027 00028 #ifndef CASA_MEMORYTRACE_H 00029 #define CASA_MEMORYTRACE_H 00030 00031 #include <casacore/casa/aips.h> 00032 #include <casacore/casa/OS/Timer.h> 00033 #include <fstream> 00034 #include <string> 00035 00036 namespace casacore { //# NAMESPACE CASACORE - BEGIN 00037 00038 // <summary>memory usage tracing mechanism</summary> 00039 // <use visibility=export> 00040 // 00041 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos=""> 00042 // </reviewed> 00043 // 00044 // <synopsis> 00045 // The MemoryTrace class provides some means to trace the 00046 // memory usage of a program. It logs malloc and free messages in 00047 // a file which can be examined by the python script memorytrace.py. 00048 // <br>The tracing is done using hooks for malloc and free as explained 00049 // in 'man malloc_hook'. 00050 // 00051 // The tracing can be started and stopped at any time. On the first 00052 // start the trace file is created. The file can be closed at any time, 00053 // usually at the end of a program. Another start will recreate the file. 00054 // 00055 // The trace file consists of 3 types of lines: 00056 // <ul> 00057 // <li> An allocation line like "a <address> <caller> <size>" 00058 // <li> A deallocation line like "f <address> <caller>" 00059 // <li> A line like "begin/end <name>" telling the script the beginning 00060 // or end of a code block. It makes it possible to see how memory usage 00061 // develops. Such lines can be inserted using the class MemoryTraceBlock. 00062 // </ul> 00063 // All lines start with the number of milliseconds since the start of 00064 // the program. 00065 // <p> 00066 // The script memorytrace.py can be used to interpret the log file and 00067 // to show the memory usage. 00068 // </synopsis> 00069 00070 class MemoryTrace 00071 { 00072 public: 00073 // Start the tracing. Nothing is done if already started. 00074 // On the first time, it opens the trace file. The name of the 00075 // trace file can be given in the env.var. CASACORE_MEMORYTRACE. 00076 // If undefined, the name casacore_memorytrace.log will be used. 00077 static void start(); 00078 00079 // Stop the tracing. 00080 static void stop(); 00081 00082 // Open the trace file if not open yet. 00083 static void open(); 00084 00085 // Close the tracing output file. 00086 static void close(); 00087 00088 // Is tracing on? 00089 static Bool isOn() 00090 { return theirDoTrace; } 00091 00092 // Is the tracing file opened? 00093 static Bool isOpen() 00094 { return theirFile.is_open(); } 00095 00096 // Write a block line in the output file. 00097 static void writeBlock (const char* msg, const std::string& name); 00098 static void writeBlock (const char* msg, const char* name); 00099 00100 // Write an alloc or free message. 00101 static std::ofstream& writeAlloc (const void* ptr, size_t); 00102 static std::ofstream& writeFree (const void* ptr); 00103 00104 // The hooks for malloc and free writing the trace messages. 00105 static void* mallocHook (size_t, const void* caller); 00106 static void freeHook (void*, const void* caller); 00107 00108 // Make a string from a char* without tracing a possible malloc in 00109 // the string constructor. 00110 static std::string makeString (const char*); 00111 00112 private: 00113 static Bool theirDoTrace; 00114 static std::ofstream theirFile; 00115 static Timer theirTimer; 00116 //# Variables to save original hooks. 00117 static void* (*theirOldMallocHook)(size_t, const void*); 00118 static void (*theirOldFreeHook)(void*, const void*); 00119 }; 00120 00121 00122 // <summary> Class to write begin and end block message </summary> 00123 // <synopsis> 00124 // This class is meant to write memory trace messages indicating the 00125 // beginning and end of a code block. In this way it is known that the 00126 // (de)allocate messages between these messages belong to that code block. 00127 // 00128 // The constructor writes the begin message, while the destructor writes 00129 // the end message. Because the destructor is called automatically by the 00130 // compiler, the user does not have to worry about it; it will also 00131 // work fine in case of a premature exit from a function. 00132 // 00133 // It is possible to nest blocks as deeply as one likes. 00134 // </synopsis> 00135 class MemoryTraceBlock 00136 { 00137 public: 00138 // The constructor writes a block begin message. 00139 MemoryTraceBlock (const std::string& name); 00140 MemoryTraceBlock (const char* name); 00141 // The constructor writes a block end message. 00142 ~MemoryTraceBlock(); 00143 private: 00144 std::string itsName; 00145 }; 00146 00147 } //# NAMESPACE CASACORE - END 00148 00149 00150 //# Trace memory (de)allocation. 00151 #define traceMemoryAlloc(ptr,size,msg) \ 00152 if (casacore::MemoryTrace::isOpen()) { \ 00153 casacore::MemoryTrace::writeAlloc (ptr, size) << msg << std::endl; \ 00154 } 00155 #define traceMemoryFree(ptr,msg) \ 00156 if (casacore::MemoryTrace::isOpen()) { \ 00157 casacore::MemoryTrace::writeFree (ptr) << msg << std::endl; \ 00158 } 00159 00160 #define traceMemoryBlockBegin(name) \ 00161 if (casacore::MemoryTrace::isOpen()) { \ 00162 casacore::MemoryTrace::writeBlock(" begin ", name); \ 00163 } 00164 #define traceMemoryBlockEnd(name) \ 00165 if (casacore::MemoryTrace::isOpen()) { \ 00166 casacore::MemoryTrace::writeBlock(" end ", name); \ 00167 } 00168 00169 00170 #endif