memory information from /proc/... (LINUX) or api functions (Windows)

This commit is contained in:
h_vogt 2008-05-10 16:07:22 +00:00
parent b7015cb5f3
commit 77925f7f48
5 changed files with 257 additions and 65 deletions

View File

@ -1,3 +1,9 @@
2008-05-10 Holger Vogt
* src/frontend/resource.c: Memory information is now stemming from the
/proc file system (LINUX) or using GlobalMemoryStatusEx and
GetProcessMemoryInfo (Windows).
The old info system with sbrk(0) may still be used.
2008-05-06 Holger Vogt
* src/frontend/outitf.c: suppress printing of "Reference value" into log-file
under Windows

View File

@ -197,9 +197,9 @@ AC_PROG_CC
dnl the above AC_PROG_CC may set CFLAGS to "-O2 -g"
if test "$enable_debug" = "no"; then
AC_MSG_WARN(Removing debugging option!)
CFLAGS=" "
CFLAGS="-O2"
else
CFLAGS="-O0 -g"
CFLAGS="-g -O0"
fi
if test "x$GCC" = "xyes"; then
@ -269,6 +269,8 @@ case $with_windows in
CFLAGS="$CFLAGS -mwindows";;
* )
dnl Check for /proc (virtual process information file system)
AC_CHECK_HEADERS( /proc/meminfo)
dnl Checks for X11 header files and libraries - X11 support can be disabled
dnl by passing the '--without-x' option to configure:
@ -396,11 +398,6 @@ AC_CHECK_FUNCS(getrlimit ulimit, break)
AC_CHECK_FUNCS([endpwent gethostbyname memset select socket strdup strerror strncasecmp strstr strtol])
case $host_os in
*mingw* )
AC_DEFINE(HAVE__MEMAVL,1,[Get system memory from windows API])
esac
dnl Look for termios first (posix)
AC_CHECK_HEADERS(termios.h termio.h sgtty.h, break)
AC_CHECK_FUNCS(isatty tcgetattr tcsetattr)

View File

@ -212,4 +212,8 @@ INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices @X_C
LIBS = @LIBS@ @X_LIBS@ @X_PRE_LIBS@ @X_EXTRA_LIBS@
if WINDOWS
LIBS += -lpsapi
endif
MAINTAINERCLEANFILES = Makefile.in ngspice.idx

View File

@ -6,6 +6,11 @@ $Id$
/*
* Resource-related routines.
*
* New operation systems information options added:
* Windows 2000 and newer: Use GlobalMemoryStatusEx and GetProcessMemoryInfo
* LINUX (and maybe some others): Use the /proc virtual file information system
* Others: Use original code with sbrk(0) and some "ugly hacks"
*/
#include "config.h"
@ -26,9 +31,13 @@ $Id$
/* gtri - end - 12/12/90 */
#endif
#ifdef HAVE__MEMAVL
#ifdef HAS_WINDOWS
#define WIN32_LEAN_AND_MEAN
/* At least Windows 2000 is needed
* Undefine _WIN32_WINNT 0x0500 if you want to compile under Windows ME
* and older (not tested under Windows ME or 98!)
*/
#define _WIN32_WINNT 0x0500
/*
* The ngspice.h file included above defines BOOLEAN (via bool.h) and this
* clashes with the definition obtained from windows.h (via winnt.h).
@ -38,41 +47,40 @@ $Id$
*/
#undef BOOLEAN
#include <windows.h>
#if ( _WIN32_WINNT >= 0x0500)
#include <psapi.h>
#endif
#endif
/* Uncheck the following definition if you want to get the old usage information
#undef HAVE__PROC_MEMINFO
*/
/* static declarations */
static void printres(char *name);
static void fprintmem(FILE* stream, size_t memory);
#ifndef HAVE__MEMAVL
static void fprintmem(FILE* stream, unsigned long int memory);
#if defined(HAS_WINDOWS) || defined(HAVE__PROC_MEMINFO)
static size_t get_procm(struct proc_mem *memall);
static size_t get_sysmem(struct sys_mem *memall);
struct sys_mem mem_t, mem_t_act;
struct proc_mem mem_ng, mem_ng_act;
#else
static RETSIGTYPE fault(void);
static void * baseaddr(void);
#endif
#ifdef HAVE__MEMAVL
size_t mem_avail;
size_t _memavl(void)
{
MEMORYSTATUS ms;
DWORD sum;
ms.dwLength = sizeof(MEMORYSTATUS);
GlobalMemoryStatus( &ms);
sum = ms.dwAvailPhys + ms.dwAvailPageFile;
return (size_t) sum;
}
#else
char *startdata;
char *enddata;
#endif
void
init_rlimits(void)
{
# ifdef HAVE__MEMAVL /* hvogt */
mem_avail = _memavl( );
# if defined(HAS_WINDOWS) || defined(HAVE__PROC_MEMINFO)
get_procm(&mem_ng);
get_sysmem(&mem_t);
# else
startdata = (char *) baseaddr( );
enddata = sbrk(0);
@ -127,31 +135,29 @@ char* copyword;
void
ft_ckspace(void)
{
size_t usage, limit;
unsigned long int usage, limit;
#ifdef HAVE__MEMAVL
size_t mem_avail_now;
mem_avail_now = _memavl( );
usage = mem_avail - mem_avail_now;
limit = mem_avail;
#else /* HAVE__MEMAVL */
static size_t old_usage = 0;
#if defined(HAS_WINDOWS) || defined(HAVE__PROC_MEMINFO)
get_procm(&mem_ng_act);
usage = mem_ng_act.size*1024;
limit = mem_t.free;
#else
static unsigned long int old_usage = 0;
char *hi;
# ifdef HAVE_GETRLIMIT
#ifdef HAVE_GETRLIMIT
struct rlimit rld;
getrlimit(RLIMIT_DATA, &rld);
if (rld.rlim_cur == RLIM_INFINITY)
return;
limit = rld.rlim_cur - (enddata - startdata); /* rlim_max not used */
# else /* HAVE_GETRLIMIT */
#else /* HAVE_GETRLIMIT */
/* SYSVRLIMIT */
limit = ulimit(3, 0L) - (enddata - startdata);
# endif /* HAVE_GETRLIMIT */
#endif /* HAVE_GETRLIMIT */
hi=sbrk(0);
usage = (size_t) (hi - enddata);
usage = (unsigned long int) (hi - enddata);
if (limit < 0)
return; /* what else do you do? */
@ -160,7 +166,7 @@ ft_ckspace(void)
return;
old_usage = usage;
#endif /* HAVE__MEMAVL */
#endif /* not HAS_WINDOWS */
if (usage > limit * 0.9) {
fprintf(cp_err, "Warning - approaching max data size: ");
@ -248,7 +254,7 @@ printres(char *name)
lastusec -= 1000;
lastsec += 1;
}
#ifndef HAVE__MEMAVL
#ifndef HAS_WINDOWS
fprintf(cp_out, "%s time since last call: %lu.%03lu seconds.\n",
cpu_elapsed, lastsec, lastusec);
#endif
@ -278,15 +284,7 @@ printres(char *name)
}
if (!name || eq(name, "space")) {
size_t usage = 0, limit = 0;
#ifdef HAVE__MEMAVL
size_t mem_avail_now;
mem_avail_now = _memavl( );
usage = mem_avail - mem_avail_now;
limit = mem_avail;
#else /* HAVE__MEMAVL */
unsigned long int usage = 0, limit = 0;
#ifdef ipsc
NXINFO cur = nxinfo, start = nxinfo_snap;
@ -301,19 +299,62 @@ printres(char *name)
getrlimit(RLIMIT_DATA, &rld);
limit = rld.rlim_cur - (enddata - startdata);
hi = sbrk(0);
usage = (size_t) (hi - enddata);
usage = (unsigned long int) (hi - enddata);
# else /* HAVE_GETRLIMIT */
# ifdef HAVE_ULIMIT
char *hi;
limit = ulimit(3, 0L) - (enddata - startdata);
hi = sbrk(0);
usage = (size_t) (hi - enddata);
usage = (unsigned long int) (hi - enddata);
# endif /* HAVE_ULIMIT */
# endif /* HAVE_GETRLIMIT */
#endif /* ipsc */
#endif /* HAVE__MEMAVL */
#if defined(HAS_WINDOWS) || defined(HAVE__PROC_MEMINFO)
get_procm(&mem_ng_act);
get_sysmem(&mem_t_act);
/* get_sysmem returns bytes */
fprintf(cp_out, "Total DRAM available = ");
fprintmem(cp_out, mem_t_act.size);
fprintf(cp_out, ".\n");
fprintf(cp_out, "DRAM currently available = ");
fprintmem(cp_out, mem_t_act.free);
fprintf(cp_out, ".\n");
/* get_procm returns Kilobytes */
fprintf(cp_out, "Total ngspice program size = ");
fprintmem(cp_out, mem_ng_act.size*1024);
fprintf(cp_out, ".\n");
#if defined(HAVE__PROC_MEMINFO)
fprintf(cp_out, "Resident set size = ");
fprintmem(cp_out, mem_ng_act.resident*1024);
fprintf(cp_out, ".\n");
fprintf(cp_out, "Shared ngspice pages = ");
fprintmem(cp_out, mem_ng_act.shared*1024);
fprintf(cp_out, ".\n");
fprintf(cp_out, "Text (code) pages = ");
fprintmem(cp_out, mem_ng_act.trs*1024);
fprintf(cp_out, ".\n");
fprintf(cp_out, "Stack = ");
fprintmem(cp_out, mem_ng_act.drs*1024);
fprintf(cp_out, ".\n");
fprintf(cp_out, "Library pages = ");
fprintmem(cp_out, mem_ng_act.lrs*1024);
fprintf(cp_out, ".\n");
/* not used
fprintf(cp_out, "Dirty pages = ");
fprintmem(cp_out, all_memory.dt * 1024);
fprintf(cp_out, ".\n"); */
#endif /* HAVE__PROC_MEMINFO */
#else /* HAS_WINDOWS or HAVE__PROC_MEMINFO */
fprintf(cp_out, "Current dynamic memory usage = ");
fprintmem(cp_out, usage);
fprintf(cp_out, ",\n");
@ -321,7 +362,7 @@ printres(char *name)
fprintf(cp_out, "Dynamic memory limit = ");
fprintmem(cp_out, limit);
fprintf(cp_out, ".\n");
#endif
yy = TRUE;
}
@ -395,17 +436,139 @@ printres(char *name)
/* Print to stream the given memory size in a human friendly format */
static void
fprintmem(FILE* stream, size_t memory) {
if (memory > 1000000)
fprintf(stream, "%8.6f MB", memory/1000000.);
else if (memory > 1000)
fprintf(stream, "%5.3f kB", memory/1000.);
fprintmem(FILE* stream, unsigned long int memory) {
if (memory > 1048576)
fprintf(stream, "%8.6f MB", memory/1048576.);
else if (memory > 1024)
fprintf(stream, "%5.3f kB", memory/1024.);
else
fprintf(stream, "%lu bytes", (unsigned long)memory);
fprintf(stream, "%lu bytes", memory);
}
# if defined(HAS_WINDOWS) || defined(HAVE__PROC_MEMINFO)
static size_t get_procm(struct proc_mem *memall) {
#ifdef HAS_WINDOWS
#if ( _WIN32_WINNT >= 0x0500)
/* Use Windows Api function to obtain size of memory */
HANDLE hProcess;
PROCESS_MEMORY_COUNTERS pmc;
DWORD procid = GetCurrentProcessId();
hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ,
FALSE, procid );
if (NULL == hProcess)
return 0;
/* psapi library required */
if ( GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)) ) {
memall->size = pmc.WorkingSetSize/1024;
memall->resident = pmc.QuotaNonPagedPoolUsage/1024;
memall->trs = pmc.QuotaPagedPoolUsage/1024;
}
else {
CloseHandle( hProcess );
return 0;
}
CloseHandle( hProcess );
#else
/* ngspice size is just the difference between free memory at start time and now */
get_sysmem(&mem_t_act);
memall->size = mem_t.free - mem_t_act.free;
memall->resident = 0;
memall->trs = 0;
#endif /* _WIN32_WINNT 0x0500 */
#else
/* Use /proc/<pid>/statm file information */
FILE *fp;
char buffer[1024], fibuf[100];
size_t bytes_read;
(void) sprintf(fibuf, "/proc/%d/statm", getpid());
if((fp = fopen(fibuf, "r")) == NULL) {
perror("fopen()");
return 0;
}
bytes_read = fread (buffer, 1, sizeof (buffer), fp);
fclose (fp);
if (bytes_read == 0 || bytes_read == sizeof (buffer))
return 0;
buffer[bytes_read] = '\0';
sscanf (buffer, "%d %d %d %d %d %d %d", &memall->size, &memall->resident, &memall->shared, &memall->trs, &memall->drs, &memall->lrs, &memall->dt);
#endif
return 1;
}
static size_t get_sysmem(struct sys_mem *memall) {
#ifdef HAS_WINDOWS
#if ( _WIN32_WINNT >= 0x0500)
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(MEMORYSTATUSEX);
GlobalMemoryStatusEx( &ms);
memall->size = ms.ullTotalPhys;
memall->free = ms.ullAvailPhys;
memall->swap_t = ms.ullTotalPageFile;
memall->swap_f = ms.ullAvailPageFile;
#else
MEMORYSTATUS ms;
ms.dwLength = sizeof(MEMORYSTATUS);
GlobalMemoryStatus( &ms);
memall->size = ms.dwTotalPhys;
memall->free = ms.dwAvailPhys;
memall->swap_t = ms.dwTotalPageFile;
memall->swap_f = ms.dwAvailPageFile;
#endif /*_WIN32_WINNT 0x0500*/
#else
FILE *fp;
char buffer[1024];
size_t bytes_read;
char *match;
long mem_got;
if((fp = fopen("/proc/meminfo", "r")) == NULL) {
perror("fopen()");
return 0;
}
bytes_read = fread (buffer, 1, sizeof (buffer), fp);
fclose (fp);
if (bytes_read == 0 || bytes_read == sizeof (buffer))
return 0;
buffer[bytes_read] = '\0';
/* Search for string "MemTotal" */
match = strstr (buffer, "MemTotal");
if (match == NULL) /* not found */
return 0;
sscanf (match, "MemTotal: %ld", &mem_got);
memall->size = mem_got*1024; /* 1MB = 1024KB */
/* Search for string "MemFree" */
match = strstr (buffer, "MemFree");
if (match == NULL) /* not found */
return 0;
sscanf (match, "MemFree: %ld", &mem_got);
memall->free = mem_got*1024; /* 1MB = 1024KB */
/* Search for string "SwapTotal" */
match = strstr (buffer, "SwapTotal");
if (match == NULL) /* not found */
return 0;
sscanf (match, "SwapTotal: %ld", &mem_got);
memall->swap_t = mem_got*1024; /* 1MB = 1024KB */
/* Search for string "SwapFree" */
match = strstr (buffer, "SwapFree");
if (match == NULL) /* not found */
return 0;
sscanf (match, "SwapFree: %ld", &mem_got);
memall->swap_f = mem_got*1024; /* 1MB = 1024KB */
#endif
return 1;
}
#ifndef HAVE__MEMAVL
#else
#include <signal.h>
#include <setjmp.h>
@ -479,8 +642,12 @@ baseaddr(void)
#endif
}
#endif
# ifdef notdef
main( )
{
@ -489,3 +656,4 @@ main( )
}
# endif

View File

@ -12,4 +12,21 @@ void com_rusage(wordlist *wl);
void ft_ckspace(void);
struct proc_mem {
size_t size; /* Total ngspice program size */
size_t resident;/* Resident set size */
size_t shared; /* Shared ngspice pages */
size_t trs; /* Text (code) pages */
size_t drs; /* Stack */
size_t lrs; /* Library pages */
size_t dt; /* Dirty pages (not used in kernel 2.6) */
};
struct sys_mem {
unsigned long int size; /* Total memory size */
unsigned long int free; /* Free memory */
unsigned long int swap_t; /* Swap total */
unsigned long int swap_f; /* Swap free */
};
#endif