blob: 4462c455c5e702d3799b0e286dcda050cdad98df [file] [log] [blame]
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/agent/hardware/memory.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/ps/IOPowerSources.h>
/*
* Retained from UCD implementation
*/
/*
* Get the number of pages that are swapped out.
* We think this is correct and are valid values
* but not sure. Time will tell if it's correct.
* Note: this routine is _expensive_!!! we run this
* as little as possible by caching it's return so
* it's not run on every poll.
* Apple, please give us a better way! :)
*/
int pages_swapped(void) {
boolean_t retval;
kern_return_t error;
processor_set_t *psets, pset;
task_t *tasks;
unsigned i, j, pcnt, tcnt;
int pid;
mach_msg_type_number_t count;
vm_address_t address;
mach_port_t object_name;
vm_region_extended_info_data_t info;
vm_size_t size;
mach_port_t mach_port;
int swapped_pages;
int swapped_pages_total = 0;
char errmsg[1024];
mach_port = mach_host_self();
error = host_processor_sets(mach_port, &psets, &pcnt);
if (error != KERN_SUCCESS) {
snmp_log(LOG_ERR, "Error in host_processor_sets(): %s\n", mach_error_string(error));
return(0);
}
for (i = 0; i < pcnt; i++) {
error = host_processor_set_priv(mach_port, psets[i], &pset);
if (error != KERN_SUCCESS) {
snprintf(errmsg, sizeof(errmsg),"Error in host_processor_set_priv(): %s\n", mach_error_string(error));
snmp_log_perror(errmsg);
return(0);
}
error = processor_set_tasks(pset, &tasks, &tcnt);
if (error != KERN_SUCCESS) {
snprintf(errmsg, sizeof(errmsg),"Error in processor_set_tasks(): %s\n", mach_error_string(error));
snmp_log_perror(errmsg);
return(0);
}
for (j = 0; j < tcnt; j++) {
error = pid_for_task(tasks[j], &pid);
if (error != KERN_SUCCESS) {
/* Not a process, or the process is gone. */
continue;
}
swapped_pages = 0;
for (address = 0;; address += size) {
/* Get memory region. */
count = VM_REGION_EXTENDED_INFO_COUNT;
#if defined(__ppc64__) || defined(__x86_64__)
if (vm_region_64(tasks[j], &address, &size, VM_REGION_EXTENDED_INFO, &info, &count, &object_name) != KERN_SUCCESS) {
#else
if (vm_region(tasks[j], &address, &size, VM_REGION_EXTENDED_INFO, &info, &count, &object_name) != KERN_SUCCESS) {
#endif
/* No more memory regions. */
break;
}
if(info.pages_swapped_out > 0) {
swapped_pages += info.pages_swapped_out;
}
}
if(swapped_pages > 0) {
swapped_pages_total += swapped_pages;
}
if (tasks[j] != mach_task_self()) {
mach_port_deallocate(mach_task_self(), tasks[j]);
}
}
}
return(swapped_pages_total);
}
off_t
swapsize(void)
{
int pagesize;
int i, n;
DIR *dirp;
struct dirent *dp;
struct stat buf;
char errmsg[1024];
char full_name[1024];
off_t swapSize;
/* we set the size to -1 if we're not supported */
swapSize = -1;
#if defined(SWAPFILE_DIR) && defined(SWAPFILE_PREFIX)
dirp = opendir((const char *) SWAPFILE_DIR);
while((dp = readdir(dirp)) != NULL) {
/* if the file starts with the same as SWAPFILE_PREFIX
* we want to stat the file to get it's size
*/
if(strspn(dp->d_name,(char *) SWAPFILE_PREFIX) == strlen((char *) SWAPFILE_PREFIX)) {
snprintf(full_name, sizeof(full_name),"%s/%s",SWAPFILE_DIR,dp->d_name);
/* we need to stat each swapfile to get it's size */
if(stat(full_name,&buf) != 0) {
snprintf(errmsg, sizeof(errmsg), "swapsize: can't stat file %s",full_name);
snmp_log_perror(errmsg);
} else {
/* total swap allocated is the size of
* all the swapfile's that exist in
* the SWAPFILE_DIR dir
*/
swapSize += buf.st_size;
}
}
}
closedir(dirp);
#else
/* we set the size to -1 if we're not supported */
swapSize = -1;
#endif
return swapSize;
}
/*
* Load the latest memory usage statistics
*
* HW_PHYSMEM is capped at 2 Gigs so we use HW_MEMSIZE
*/
int netsnmp_mem_arch_load( netsnmp_cache *cache, void *magic ) {
netsnmp_memory_info *mem;
uint64_t phys_mem; /* bytes */
size_t phys_mem_size = sizeof(phys_mem);
int phys_mem_mib[] = { CTL_HW, HW_MEMSIZE };
int pagesize; /* bytes */
size_t pagesize_size = sizeof(pagesize);
int pagesize_mib[] = { CTL_HW, HW_PAGESIZE };
uint64_t pages_used;
off_t swapSize;
off_t swapUsed;
vm_statistics_data_t vm_stat;
unsigned int count = HOST_VM_INFO_COUNT;
sysctl(phys_mem_mib, 2, &phys_mem, &phys_mem_size, NULL, 0);
sysctl(pagesize_mib, 2, &pagesize, &pagesize_size, NULL, 0);
host_statistics(mach_host_self(),HOST_VM_INFO,(host_info_t)&vm_stat,&count);
pages_used = vm_stat.active_count + vm_stat.inactive_count
+ vm_stat.wire_count;
swapSize = swapsize(); /* in bytes */
swapUsed = pages_swapped();
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_PHYSMEM, 1 );
if (!mem) {
snmp_log_perror("No Memory info entry");
} else {
if (!mem->descr)
mem->descr = strdup( "Physical memory" );
mem->units = pagesize; /* 4096 */
mem->size = phys_mem/pagesize;
mem->free = (phys_mem/pagesize) - pages_used;
mem->other = -1;
}
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_SWAP, 1 );
if (!mem) {
snmp_log_perror("No Swap info entry");
} else {
if (!mem->descr)
mem->descr = strdup( "Swap space" );
mem->units = pagesize; /* 4096 */
mem->size = swapSize/pagesize;
mem->free = (swapSize/pagesize) - swapUsed;
mem->other = -1;
}
/*
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_MISC, 1 );
if (!mem) {
snmp_log_perror("No Buffer, etc info entry");
} else {
mem->units = pagesize;
mem->size = -1;
mem->free = (phys_mem - pages_used) + (swapSize - swapUsed);
mem->other = -1;
}
*/
return 0;
}