llmemory.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 #if defined(LL_WINDOWS)
00035 # include <windows.h>
00036 # include <psapi.h>
00037 #elif defined(LL_DARWIN)
00038 # include <sys/types.h>
00039 # include <sys/sysctl.h>
00040 # include <mach/task.h>
00041 # include <mach/vm_map.h>
00042 # include <mach/mach_init.h>
00043 # include <mach/vm_region.h>
00044 # include <mach/mach_port.h>
00045 #elif defined(LL_LINUX)
00046 # include <unistd.h>
00047 #endif
00048 
00049 #include "llmemory.h"
00050 #include "llmemtype.h"
00051 
00052 //----------------------------------------------------------------------------
00053 
00054 //static
00055 char* LLMemory::reserveMem = 0;
00056 
00057 //static
00058 void LLMemory::initClass()
00059 {
00060         if (!reserveMem)
00061         {
00062                 reserveMem = new char[16*1024]; // reserve 16K for out of memory error handling
00063         }
00064 }
00065 
00066 //static
00067 void LLMemory::cleanupClass()
00068 {
00069         delete [] reserveMem;
00070         reserveMem = NULL;
00071 }
00072 
00073 //static
00074 void LLMemory::freeReserve()
00075 {
00076         delete [] reserveMem;
00077         reserveMem = NULL;
00078 }
00079 
00080 
00081 //----------------------------------------------------------------------------
00082 
00083 //static
00084 #if MEM_TRACK_TYPE
00085 S32 LLMemType::sCurDepth = 0;
00086 S32 LLMemType::sCurType = LLMemType::MTYPE_INIT;
00087 S32 LLMemType::sType[LLMemType::MTYPE_MAX_DEPTH];
00088 S32 LLMemType::sMemCount[LLMemType::MTYPE_NUM_TYPES] = { 0 };
00089 S32 LLMemType::sMaxMemCount[LLMemType::MTYPE_NUM_TYPES] = { 0 };
00090 S32 LLMemType::sNewCount[LLMemType::MTYPE_NUM_TYPES] = { 0 };
00091 S32 LLMemType::sOverheadMem = 0;
00092 
00093 const char* LLMemType::sTypeDesc[LLMemType::MTYPE_NUM_TYPES] =
00094 {
00095         "INIT",
00096         "STARTUP",
00097         "MAIN",
00098         
00099         "IMAGEBASE",
00100         "IMAGERAW",
00101         "IMAGEFORMATTED",
00102         
00103         "APPFMTIMAGE",
00104         "APPRAWIMAGE",
00105         "APPAUXRAWIMAGE",
00106         
00107         "DRAWABLE",
00108         "OBJECT",
00109         "PIPELINE",
00110         "AVATAR",
00111         "PARTICLES",
00112         "REGIONS",
00113         "INVENTORY",
00114         "ANIMATION",
00115         "NETWORK",
00116         "PHYSICS",
00117         "INTERESTLIST",
00118         
00119         "SCRIPT",
00120         "SCRIPT_RUN",
00121         "SCRIPT_BYTECODE",
00122         
00123         "IO_PUMP",
00124         "IO_TCP",
00125         "IO_BUFFER",
00126         "IO_HTTP_SERVER"
00127         "IO_SD_SERVER",
00128         "IO_SD_CLIENT",
00129         "IO_URL_REQUEST",
00130 
00131         "TEMP1",
00132         "TEMP2",
00133         "TEMP3",
00134         "TEMP4",
00135         "TEMP5",
00136         "TEMP6",
00137         "TEMP7",
00138         "TEMP8",
00139         "TEMP9"
00140 };
00141 
00142 #endif
00143 S32 LLMemType::sTotalMem = 0;
00144 S32 LLMemType::sMaxTotalMem = 0;
00145 
00146 //static
00147 void LLMemType::printMem()
00148 {
00149         S32 misc_mem = sTotalMem;
00150 #if MEM_TRACK_TYPE
00151         for (S32 i=0; i<MTYPE_NUM_TYPES; i++)
00152         {
00153                 if (sMemCount[i])
00154                 {
00155                         llinfos << llformat("MEM: % 20s %03d MB (%03d MB) in %06d News",sTypeDesc[i],sMemCount[i]>>20,sMaxMemCount[i]>>20, sNewCount[i]) << llendl;
00156                 }
00157                 misc_mem -= sMemCount[i];
00158         }
00159 #endif
00160         llinfos << llformat("MEM: % 20s %03d MB","MISC",misc_mem>>20) << llendl;
00161         llinfos << llformat("MEM: % 20s %03d MB (Max=%d MB)","TOTAL",sTotalMem>>20,sMaxTotalMem>>20) << llendl;
00162 }
00163 
00164 #if MEM_TRACK_MEM
00165 
00166 void* ll_allocate (size_t size)
00167 {
00168         if (size == 0)
00169         {
00170                 llwarns << "Null allocation" << llendl;
00171         }
00172         
00173         size = (size+3)&~3;
00174         S32 alloc_size = size + 4;
00175 #if MEM_TRACK_TYPE
00176         alloc_size += 4;
00177 #endif
00178         char* p = (char*)malloc(alloc_size);
00179         if (p == NULL)
00180         {
00181                 LLMemory::freeReserve();
00182                 llerrs << "Out of memory Error" << llendl;
00183         }
00184         LLMemType::sTotalMem += size;
00185         LLMemType::sMaxTotalMem = llmax(LLMemType::sTotalMem, LLMemType::sMaxTotalMem);
00186         LLMemType::sOverheadMem += 4;
00187         *(size_t*)p = size;
00188         p += 4;
00189 #if MEM_TRACK_TYPE
00190         if (LLMemType::sCurType < 0 || LLMemType::sCurType >= LLMemType::MTYPE_NUM_TYPES)
00191         {
00192                 llerrs << "Memory Type Error: new" << llendl;
00193         }
00194         LLMemType::sOverheadMem += 4;
00195         *(S32*)p = LLMemType::sCurType;
00196         p += 4;
00197         LLMemType::sMemCount[LLMemType::sCurType] += size;
00198         if (LLMemType::sMemCount[LLMemType::sCurType] > LLMemType::sMaxMemCount[LLMemType::sCurType])
00199         {
00200                 LLMemType::sMaxMemCount[LLMemType::sCurType] = LLMemType::sMemCount[LLMemType::sCurType];
00201         }
00202         LLMemType::sNewCount[LLMemType::sCurType]++;
00203 #endif
00204         return (void*)p;
00205 }
00206 
00207 void ll_release (void *pin)
00208 {
00209         if (!pin)
00210         {
00211                 return;
00212         }
00213         char* p = (char*)pin;
00214 #if MEM_TRACK_TYPE
00215         p -= 4;
00216         S32 type = *(S32*)p;
00217         if (type < 0 || type >= LLMemType::MTYPE_NUM_TYPES)
00218         {
00219                 llerrs << "Memory Type Error: delete" << llendl;
00220         }
00221 #endif
00222         p -= 4;
00223         S32 size = *(size_t*)p;
00224         LLMemType::sOverheadMem -= 4;
00225 #if MEM_TRACK_TYPE
00226         LLMemType::sMemCount[type] -= size;
00227         LLMemType::sOverheadMem -= 4;
00228         LLMemType::sNewCount[type]--;
00229 #endif
00230         LLMemType::sTotalMem -= size;
00231         free(p);
00232 }
00233 
00234 #else
00235 
00236 void* ll_allocate (size_t size)
00237 {
00238         if (size == 0)
00239         {
00240                 llwarns << "Null allocation" << llendl;
00241         }
00242         void *p = malloc(size);
00243         if (p == NULL)
00244         {
00245                 LLMemory::freeReserve();
00246                 llerrs << "Out of memory Error" << llendl;
00247         }
00248         return p;
00249 }
00250 
00251 void ll_release (void *p)
00252 {
00253         free(p);
00254 }
00255 
00256 #endif
00257 
00258 #if MEM_TRACK_MEM
00259 
00260 void* operator new (size_t size)
00261 {
00262         return ll_allocate(size);
00263 }
00264 
00265 void* operator new[] (size_t size)
00266 {
00267         return ll_allocate(size);
00268 }
00269 
00270 void operator delete (void *p)
00271 {
00272         ll_release(p);
00273 }
00274 
00275 void operator delete[] (void *p)
00276 {
00277         ll_release(p);
00278 }
00279 
00280 #endif
00281 
00282 //----------------------------------------------------------------------------
00283 
00284 LLRefCount::LLRefCount() :
00285         mRef(0)
00286 {
00287 }
00288 
00289 LLRefCount::~LLRefCount()
00290 { 
00291         if (mRef != 0)
00292         {
00293                 llerrs << "deleting non-zero reference" << llendl;
00294         }
00295 }
00296         
00297 //----------------------------------------------------------------------------
00298 
00299 #if defined(LL_WINDOWS)
00300 
00301 U64 getCurrentRSS()
00302 {
00303         HANDLE self = GetCurrentProcess();
00304         PROCESS_MEMORY_COUNTERS counters;
00305         
00306         if (!GetProcessMemoryInfo(self, &counters, sizeof(counters)))
00307         {
00308                 llwarns << "GetProcessMemoryInfo failed" << llendl;
00309                 return 0;
00310         }
00311 
00312         return counters.WorkingSetSize;
00313 }
00314 
00315 #elif defined(LL_DARWIN)
00316 
00317 static U32 getPageSize()
00318 {
00319         int ctl[2] = { CTL_HW, HW_PAGESIZE };
00320         int page_size;
00321         size_t size = sizeof(page_size);
00322 
00323         if (sysctl(ctl, 2, &page_size, &size, NULL, 0) == -1)
00324         {
00325                 llwarns << "Couldn't get page size" << llendl;
00326                 return 0;
00327         } else {
00328                 return page_size;
00329         }
00330 }
00331 
00332 U64 getCurrentRSS()
00333 {
00334         task_t task = mach_task_self();
00335         vm_address_t addr = VM_MIN_ADDRESS;
00336         vm_size_t size = 0;
00337         U64 residentPages = 0;
00338 
00339         while (true)
00340         {
00341                 mach_msg_type_number_t bcount = VM_REGION_BASIC_INFO_COUNT;
00342                 vm_region_basic_info binfo;
00343                 mach_port_t bobj;
00344                 kern_return_t ret;
00345                 
00346                 addr += size;
00347                 
00348                 ret = vm_region(task, &addr, &size, VM_REGION_BASIC_INFO,
00349                                                 (vm_region_info_t) &binfo, &bcount, &bobj);
00350                 
00351                 if (ret != KERN_SUCCESS)
00352                 {
00353                         break;
00354                 }
00355                 
00356                 if (bobj != MACH_PORT_NULL)
00357                 {
00358                         mach_port_deallocate(task, bobj);
00359                 }
00360                 
00361                 mach_msg_type_number_t ecount = VM_REGION_EXTENDED_INFO_COUNT;
00362                 vm_region_extended_info einfo;
00363                 mach_port_t eobj;
00364 
00365                 ret = vm_region(task, &addr, &size, VM_REGION_EXTENDED_INFO,
00366                                                 (vm_region_info_t) &einfo, &ecount, &eobj);
00367 
00368                 if (ret != KERN_SUCCESS)
00369                 {
00370                         llwarns << "vm_region failed" << llendl;
00371                         return 0;
00372                 }
00373                 
00374                 if (eobj != MACH_PORT_NULL)
00375                 {
00376                         mach_port_deallocate(task, eobj);
00377                 }
00378 
00379                 residentPages += einfo.pages_resident;
00380         }
00381 
00382         return residentPages * getPageSize();
00383 }
00384 
00385 #elif defined(LL_LINUX)
00386 
00387 U64 getCurrentRSS()
00388 {
00389         static const char statPath[] = "/proc/self/stat";
00390         FILE *fp = fopen(statPath, "r");
00391         U64 rss = 0;
00392 
00393         if (fp == NULL)
00394         {
00395                 llwarns << "couldn't open " << statPath << llendl;
00396                 goto bail;
00397         }
00398 
00399         // Eee-yew!      See Documentation/filesystems/proc.txt in your
00400         // nearest friendly kernel tree for details.
00401         
00402         {
00403                 int ret = fscanf(fp, "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*d %*d "
00404                                                  "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %Lu",
00405                                                  &rss);
00406                 if (ret != 1)
00407                 {
00408                         llwarns << "couldn't parse contents of " << statPath << llendl;
00409                         rss = 0;
00410                 }
00411         }
00412         
00413         fclose(fp);
00414 
00415 bail:
00416         return rss;
00417 }
00418 
00419 #else
00420 
00421 U64 getCurrentRSS()
00422 {
00423         return 0;
00424 }
00425 
00426 #endif

Generated on Thu Jul 1 06:08:51 2010 for Second Life Viewer by  doxygen 1.4.7