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
00055 char* LLMemory::reserveMem = 0;
00056
00057
00058 void LLMemory::initClass()
00059 {
00060 if (!reserveMem)
00061 {
00062 reserveMem = new char[16*1024];
00063 }
00064 }
00065
00066
00067 void LLMemory::cleanupClass()
00068 {
00069 delete [] reserveMem;
00070 reserveMem = NULL;
00071 }
00072
00073
00074 void LLMemory::freeReserve()
00075 {
00076 delete [] reserveMem;
00077 reserveMem = NULL;
00078 }
00079
00080
00081
00082
00083
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
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
00400
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