-
Steven Bennetts authored
ignore-dead-branch
Steven Bennetts authoredignore-dead-branch
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
llmemory.cpp 5.45 KiB
/**
* @file llmemory.cpp
* @brief Very special memory allocation/deallocation stuff here
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "linden_common.h"
#if defined(LL_WINDOWS)
# include <windows.h>
# include <psapi.h>
#elif defined(LL_DARWIN)
# include <sys/types.h>
# include <mach/task.h>
# include <mach/mach_init.h>
#elif LL_LINUX || LL_SOLARIS
# include <unistd.h>
#endif
#include "llmemory.h"
//----------------------------------------------------------------------------
//static
char* LLMemory::reserveMem = 0;
//static
void LLMemory::initClass()
{
if (!reserveMem)
{
reserveMem = new char[16*1024]; // reserve 16K for out of memory error handling
}
}
//static
void LLMemory::cleanupClass()
{
delete [] reserveMem;
reserveMem = NULL;
}
//static
void LLMemory::freeReserve()
{
delete [] reserveMem;
reserveMem = NULL;
}
void* ll_allocate (size_t size)
{
if (size == 0)
{
llwarns << "Null allocation" << llendl;
}
void *p = malloc(size);
if (p == NULL)
{
LLMemory::freeReserve();
llerrs << "Out of memory Error" << llendl;
}
return p;
}
void ll_release (void *p)
{
free(p);
}
//----------------------------------------------------------------------------
#if defined(LL_WINDOWS)
U64 LLMemory::getCurrentRSS()
{
HANDLE self = GetCurrentProcess();
PROCESS_MEMORY_COUNTERS counters;
if (!GetProcessMemoryInfo(self, &counters, sizeof(counters)))
{
llwarns << "GetProcessMemoryInfo failed" << llendl;
return 0;
}
return counters.WorkingSetSize;
}
#elif defined(LL_DARWIN)
/*
The API used here is not capable of dealing with 64-bit memory sizes, but is available before 10.4.
Once we start requiring 10.4, we can use the updated API, which looks like this:
task_basic_info_64_data_t basicInfo;
mach_msg_type_number_t basicInfoCount = TASK_BASIC_INFO_64_COUNT;
if (task_info(mach_task_self(), TASK_BASIC_INFO_64, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS)
Of course, this doesn't gain us anything unless we start building the viewer as a 64-bit executable, since that's the only way
for our memory allocation to exceed 2^32.
*/
// if (sysctl(ctl, 2, &page_size, &size, NULL, 0) == -1)
// {
// llwarns << "Couldn't get page size" << llendl;
// return 0;
// } else {
// return page_size;
// }
// }
U64 LLMemory::getCurrentRSS()
{
U64 residentSize = 0;
task_basic_info_data_t basicInfo;
mach_msg_type_number_t basicInfoCount = TASK_BASIC_INFO_COUNT;
if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS)
{
residentSize = basicInfo.resident_size;
// If we ever wanted it, the process virtual size is also available as:
// virtualSize = basicInfo.virtual_size;
// llinfos << "resident size is " << residentSize << llendl;
}
else
{
llwarns << "task_info failed" << llendl;
}
return residentSize;
}
#elif defined(LL_LINUX)
U64 LLMemory::getCurrentRSS()
{
static const char statPath[] = "/proc/self/stat";
LLFILE *fp = LLFile::fopen(statPath, "r");
U64 rss = 0;
if (fp == NULL)
{
llwarns << "couldn't open " << statPath << llendl;
goto bail;
}
// Eee-yew! See Documentation/filesystems/proc.txt in your
// nearest friendly kernel tree for details.
{
int ret = fscanf(fp, "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*d %*d "
"%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %Lu",
&rss);
if (ret != 1)
{
llwarns << "couldn't parse contents of " << statPath << llendl;
rss = 0;
}
}
fclose(fp);
bail:
return rss;
}
#elif LL_SOLARIS
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define _STRUCTURED_PROC 1
#include <sys/procfs.h>
U64 LLMemory::getCurrentRSS()
{
char path [LL_MAX_PATH]; /* Flawfinder: ignore */
sprintf(path, "/proc/%d/psinfo", (int)getpid());
int proc_fd = -1;
if((proc_fd = open(path, O_RDONLY)) == -1){
llwarns << "LLmemory::getCurrentRSS() unable to open " << path << ". Returning 0 RSS!" << llendl;
return 0;
}
psinfo_t proc_psinfo;
if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){
llwarns << "LLmemory::getCurrentRSS() Unable to read from " << path << ". Returning 0 RSS!" << llendl;
close(proc_fd);
return 0;
}
close(proc_fd);
return((U64)proc_psinfo.pr_rssize * 1024);
}
#else
U64 LLMemory::getCurrentRSS()
{
return 0;
}
#endif