X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fmemory.c;h=c503821ba0ce095b2241dc10689a3d60c7c11c7d;hp=799a80c31684c963172fa89363e9f931c24f4886;hb=633c3966f770e4d46651a2fe219a18d8a9907a9f;hpb=3f0d178e58251171272a643e1667abcb9946edce diff --git a/src/memory.c b/src/memory.c index 799a80c3..c503821b 100644 --- a/src/memory.c +++ b/src/memory.c @@ -1,7 +1,8 @@ /** * collectd - src/memory.c - * Copyright (C) 2005-2008 Florian octo Forster + * Copyright (C) 2005-2014 Florian octo Forster * Copyright (C) 2009 Simon Kuhnle + * Copyright (C) 2009 Manuel Sanmartin * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,8 +18,9 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Authors: - * Florian octo Forster + * Florian octo Forster * Simon Kuhnle + * Manuel Sanmartin **/ #include "collectd.h" @@ -49,6 +51,11 @@ # include #endif +#if HAVE_PERFSTAT +# include +# include +#endif /* HAVE_PERFSTAT */ + /* vm_statistics_data_t */ #if HAVE_HOST_STATISTICS static mach_port_t port_host; @@ -75,11 +82,35 @@ static int pagesize; #elif HAVE_LIBSTATGRAB /* no global variables */ /* endif HAVE_LIBSTATGRAB */ - +#elif HAVE_PERFSTAT +static int pagesize; +/* endif HAVE_PERFSTAT */ #else # error "No applicable input method." #endif +static _Bool values_absolute = 1; +static _Bool values_percentage = 0; + +static int memory_config (oconfig_item_t *ci) /* {{{ */ +{ + int i; + + for (i = 0; i < ci->children_num; i++) + { + oconfig_item_t *child = ci->children + i; + if (strcasecmp ("ValuesAbsolute", child->key) == 0) + cf_util_get_boolean (child, &values_absolute); + else if (strcasecmp ("ValuesPercentage", child->key) == 0) + cf_util_get_boolean (child, &values_percentage); + else + ERROR ("memory plugin: Invalid configuration option: " + "\"%s\".", child->key); + } + + return (0); +} /* }}} int memory_config */ + static int memory_init (void) { #if HAVE_HOST_STATISTICS @@ -116,39 +147,32 @@ static int memory_init (void) #elif HAVE_LIBSTATGRAB /* no init stuff */ -#endif /* HAVE_LIBSTATGRAB */ +/* #endif HAVE_LIBSTATGRAB */ +#elif HAVE_PERFSTAT + pagesize = getpagesize (); +#endif /* HAVE_PERFSTAT */ return (0); } /* int memory_init */ -static void memory_submit (const char *type_instance, gauge_t value) -{ - value_t values[1]; - value_list_t vl = VALUE_LIST_INIT; - - values[0].gauge = value; +#define MEMORY_SUBMIT(...) do { \ + if (values_absolute) \ + plugin_dispatch_multivalue (vl, 0, __VA_ARGS__, NULL); \ + if (values_percentage) \ + plugin_dispatch_multivalue (vl, 1, __VA_ARGS__, NULL); \ +} while (0) - vl.values = values; - vl.values_len = 1; - sstrncpy (vl.host, hostname_g, sizeof (vl.host)); - sstrncpy (vl.plugin, "memory", sizeof (vl.plugin)); - sstrncpy (vl.type, "memory", sizeof (vl.type)); - sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance)); - - plugin_dispatch_values (&vl); -} - -static int memory_read (void) +static int memory_read_internal (value_list_t *vl) { #if HAVE_HOST_STATISTICS kern_return_t status; vm_statistics_data_t vm_data; mach_msg_type_number_t vm_data_len; - long long wired; - long long active; - long long inactive; - long long free; + gauge_t wired; + gauge_t active; + gauge_t inactive; + gauge_t free; if (!port_host || !pagesize) return (-1); @@ -182,15 +206,15 @@ static int memory_read (void) * This memory is not being used. */ - wired = vm_data.wire_count * pagesize; - active = vm_data.active_count * pagesize; - inactive = vm_data.inactive_count * pagesize; - free = vm_data.free_count * pagesize; + wired = (gauge_t) (((uint64_t) vm_data.wire_count) * ((uint64_t) pagesize)); + active = (gauge_t) (((uint64_t) vm_data.active_count) * ((uint64_t) pagesize)); + inactive = (gauge_t) (((uint64_t) vm_data.inactive_count) * ((uint64_t) pagesize)); + free = (gauge_t) (((uint64_t) vm_data.free_count) * ((uint64_t) pagesize)); - memory_submit ("wired", wired); - memory_submit ("active", active); - memory_submit ("inactive", inactive); - memory_submit ("free", free); + MEMORY_SUBMIT ("wired", wired, + "active", active, + "inactive", inactive, + "free", free); /* #endif HAVE_HOST_STATISTICS */ #elif HAVE_SYSCTLBYNAME @@ -240,24 +264,25 @@ static int memory_read (void) if (!isnan (sysctl_vals[i])) sysctl_vals[i] *= sysctl_vals[0]; - memory_submit ("free", sysctl_vals[2]); - memory_submit ("wired", sysctl_vals[3]); - memory_submit ("active", sysctl_vals[4]); - memory_submit ("inactive", sysctl_vals[5]); - memory_submit ("cache", sysctl_vals[6]); + MEMORY_SUBMIT ("free", (gauge_t) sysctl_vals[2], + "wired", (gauge_t) sysctl_vals[3], + "active", (gauge_t) sysctl_vals[4], + "inactive", (gauge_t) sysctl_vals[5], + "cache", (gauge_t) sysctl_vals[6]); /* #endif HAVE_SYSCTLBYNAME */ #elif KERNEL_LINUX FILE *fh; char buffer[1024]; - + char *fields[8]; int numfields; - long long mem_used = 0; - long long mem_buffered = 0; - long long mem_cached = 0; - long long mem_free = 0; + gauge_t mem_total = 0; + gauge_t mem_used = 0; + gauge_t mem_buffered = 0; + gauge_t mem_cached = 0; + gauge_t mem_free = 0; if ((fh = fopen ("/proc/meminfo", "r")) == NULL) { @@ -267,12 +292,12 @@ static int memory_read (void) return (-1); } - while (fgets (buffer, 1024, fh) != NULL) + while (fgets (buffer, sizeof (buffer), fh) != NULL) { - long long *val = NULL; + gauge_t *val = NULL; if (strncasecmp (buffer, "MemTotal:", 9) == 0) - val = &mem_used; + val = &mem_total; else if (strncasecmp (buffer, "MemFree:", 8) == 0) val = &mem_free; else if (strncasecmp (buffer, "Buffers:", 8) == 0) @@ -282,12 +307,11 @@ static int memory_read (void) else continue; - numfields = strsplit (buffer, fields, 8); - + numfields = strsplit (buffer, fields, STATIC_ARRAY_SIZE (fields)); if (numfields < 2) continue; - *val = atoll (fields[1]) * 1024LL; + *val = 1024.0 * atof (fields[1]); } if (fclose (fh)) @@ -297,20 +321,28 @@ static int memory_read (void) sstrerror (errno, errbuf, sizeof (errbuf))); } - if (mem_used >= (mem_free + mem_buffered + mem_cached)) - { - mem_used -= mem_free + mem_buffered + mem_cached; - memory_submit ("used", mem_used); - memory_submit ("buffered", mem_buffered); - memory_submit ("cached", mem_cached); - memory_submit ("free", mem_free); - } + if (mem_total < (mem_free + mem_buffered + mem_cached)) + return (-1); + + mem_used = mem_total - (mem_free + mem_buffered + mem_cached); + MEMORY_SUBMIT ("used", mem_used, + "buffered", mem_buffered, + "cached", mem_cached, + "free", mem_free); /* #endif KERNEL_LINUX */ #elif HAVE_LIBKSTAT + /* Most of the additions here were taken as-is from the k9toolkit from + * Brendan Gregg and are subject to change I guess */ long long mem_used; long long mem_free; long long mem_lock; + long long mem_kern; + long long mem_unus; + + long long pp_kernel; + long long physmem; + long long availrmem; if (ksp == NULL) return (-1); @@ -318,25 +350,69 @@ static int memory_read (void) mem_used = get_kstat_value (ksp, "pagestotal"); mem_free = get_kstat_value (ksp, "pagesfree"); mem_lock = get_kstat_value (ksp, "pageslocked"); + mem_kern = 0; + mem_unus = 0; + + pp_kernel = get_kstat_value (ksp, "pp_kernel"); + physmem = get_kstat_value (ksp, "physmem"); + availrmem = get_kstat_value (ksp, "availrmem"); if ((mem_used < 0LL) || (mem_free < 0LL) || (mem_lock < 0LL)) + { + WARNING ("memory plugin: one of used, free or locked is negative."); return (-1); + } + + mem_unus = physmem - mem_used; + if (mem_used < (mem_free + mem_lock)) - return (-1); + { + /* source: http://wesunsolve.net/bugid/id/4909199 + * this seems to happen when swap space is small, e.g. 2G on a 32G system + * we will make some assumptions here + * educated solaris internals help welcome here */ + DEBUG ("memory plugin: pages total is smaller than \"free\" " + "+ \"locked\". This is probably due to small " + "swap space"); + mem_free = availrmem; + mem_used = 0; + } + else + { + mem_used -= mem_free + mem_lock; + } + + /* mem_kern is accounted for in mem_lock */ + if (pp_kernel < mem_lock) + { + mem_kern = pp_kernel; + mem_lock -= pp_kernel; + } + else + { + mem_kern = mem_lock; + mem_lock = 0; + } - mem_used -= mem_free + mem_lock; mem_used *= pagesize; /* If this overflows you have some serious */ mem_free *= pagesize; /* memory.. Why not call me up and give me */ mem_lock *= pagesize; /* some? ;) */ - - memory_submit ("used", mem_used); - memory_submit ("free", mem_free); - memory_submit ("locked", mem_lock); + mem_kern *= pagesize; /* it's 2011 RAM is cheap */ + mem_unus *= pagesize; + + MEMORY_SUBMIT ("used", (gauge_t) mem_used, + "free", (gauge_t) mem_free, + "locked", (gauge_t) mem_lock, + "kernel", (gauge_t) mem_kern, + "unusable", (gauge_t) mem_unus); /* #endif HAVE_LIBKSTAT */ #elif HAVE_SYSCTL int mib[] = {CTL_VM, VM_METER}; struct vmtotal vmtotal; + gauge_t mem_active; + gauge_t mem_inactive; + gauge_t mem_free; size_t size; memset (&vmtotal, 0, sizeof (vmtotal)); @@ -350,27 +426,76 @@ static int memory_read (void) } assert (pagesize > 0); - memory_submit ("active", vmtotal.t_arm * pagesize); - memory_submit ("inactive", (vmtotal.t_rm - vmtotal.t_arm) * pagesize); - memory_submit ("free", vmtotal.t_free * pagesize); + mem_active = (gauge_t) (vmtotal.t_arm * pagesize); + mem_inactive = (gauge_t) ((vmtotal.t_rm - vmtotal.t_arm) * pagesize); + mem_free = (gauge_t) (vmtotal.t_free * pagesize); + + MEMORY_SUBMIT ("active", mem_active, + "inactive", mem_inactive, + "free", mem_free); /* #endif HAVE_SYSCTL */ #elif HAVE_LIBSTATGRAB sg_mem_stats *ios; - if ((ios = sg_get_mem_stats ()) != NULL) + ios = sg_get_mem_stats (); + if (ios == NULL) + return (-1); + + MEMORY_SUBMIT ("used", (gauge_t) ios->used, + "cached", (gauge_t) ios->cache, + "free", (gauge_t) ios->free); +/* #endif HAVE_LIBSTATGRAB */ + +#elif HAVE_PERFSTAT + perfstat_memory_total_t pmemory; + + memset (&pmemory, 0, sizeof (pmemory)); + if (perfstat_memory_total(NULL, &pmemory, sizeof(pmemory), 1) < 0) { - memory_submit ("used", ios->used); - memory_submit ("cached", ios->cache); - memory_submit ("free", ios->free); + char errbuf[1024]; + WARNING ("memory plugin: perfstat_memory_total failed: %s", + sstrerror (errno, errbuf, sizeof (errbuf))); + return (-1); } -#endif /* HAVE_LIBSTATGRAB */ + + /* Unfortunately, the AIX documentation is not very clear on how these + * numbers relate to one another. The only thing is states explcitly + * is: + * real_total = real_process + real_free + numperm + real_system + * + * Another segmentation, which would be closer to the numbers reported + * by the "svmon" utility, would be: + * real_total = real_free + real_inuse + * real_inuse = "active" + real_pinned + numperm + */ + MEMORY_SUBMIT ("free", (gauge_t) (pmemory.real_free * pagesize), + "cached", (gauge_t) (pmemory.numperm * pagesize), + "system", (gauge_t) (pmemory.real_system * pagesize), + "user", (gauge_t) (pmemory.real_process * pagesize)); +#endif /* HAVE_PERFSTAT */ return (0); -} +} /* }}} int memory_read_internal */ + +static int memory_read (void) /* {{{ */ +{ + value_t v[1]; + value_list_t vl = VALUE_LIST_INIT; + + vl.values = v; + vl.values_len = STATIC_ARRAY_SIZE (v); + sstrncpy (vl.host, hostname_g, sizeof (vl.host)); + sstrncpy (vl.plugin, "memory", sizeof (vl.plugin)); + sstrncpy (vl.type, "memory", sizeof (vl.type)); + vl.time = cdtime (); + + return (memory_read_internal (&vl)); +} /* }}} int memory_read */ void module_register (void) { + plugin_register_complex_config ("memory", memory_config); plugin_register_init ("memory", memory_init); plugin_register_read ("memory", memory_read); } /* void module_register */