X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fmemory.c;h=16b8e09fbac720d6c32f7a919bf2f46cc793713e;hb=4d370741101aeb037ae52f3529a4a0869e0dc08a;hp=7f477ec5fd350b4394cbd1ca4068252e4983a926;hpb=1aa8032d546fec75d3ad8b7cccfe373a272dfe63;p=collectd.git diff --git a/src/memory.c b/src/memory.c index 7f477ec5..16b8e09f 100644 --- a/src/memory.c +++ b/src/memory.c @@ -1,6 +1,6 @@ /** * 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 * @@ -18,18 +18,22 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Authors: - * Florian octo Forster + * Florian octo Forster * Simon Kuhnle * Manuel Sanmartin **/ #include "collectd.h" + #include "common.h" #include "plugin.h" #ifdef HAVE_SYS_SYSCTL_H # include #endif +#ifdef HAVE_SYS_VMMETER_H +# include +#endif #ifdef HAVE_MACH_KERN_RETURN_H # include @@ -73,6 +77,7 @@ static vm_size_t pagesize; #elif HAVE_LIBKSTAT static int pagesize; static kstat_t *ksp; +static kstat_t *ksz; /* #endif HAVE_LIBKSTAT */ #elif HAVE_SYSCTL @@ -84,7 +89,6 @@ static int pagesize; /* endif HAVE_LIBSTATGRAB */ #elif HAVE_PERFSTAT static int pagesize; -static perfstat_memory_total_t pmemory; /* endif HAVE_PERFSTAT */ #else # error "No applicable input method." @@ -93,34 +97,21 @@ static perfstat_memory_total_t pmemory; static _Bool values_absolute = 1; static _Bool values_percentage = 0; -static const char *config_keys[] = -{ - "ValuesAbsolute", - "ValuesPercentage" -}; -static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); - -static int memory_config (const char *key, const char *value) /* {{{ */ +static int memory_config (oconfig_item_t *ci) /* {{{ */ { - if (strcasecmp (key, "ValuesAbsolute") == 0) + for (int i = 0; i < ci->children_num; i++) { - if (IS_TRUE (value)) - values_absolute = 1; + 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 - values_absolute = 0; - - return (0); + ERROR ("memory plugin: Invalid configuration option: " + "\"%s\".", child->key); } - else if (strcasecmp (key, "ValuesPercentage") == 0) - { - if (IS_TRUE (value)) - values_percentage = 1; - else - values_percentage = 0; - return (0); - } - return (-1); + return (0); } /* }}} int memory_config */ static int memory_init (void) @@ -146,6 +137,12 @@ static int memory_init (void) ksp = NULL; return (-1); } + if (get_kstat (&ksz, "zfs", 0, "arcstats") != 0) + { + ksz = NULL; + return (-1); + } + /* #endif HAVE_LIBKSTAT */ #elif HAVE_SYSCTL @@ -167,24 +164,14 @@ static int memory_init (void) 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; - - 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); -} +#define MEMORY_SUBMIT(...) do { \ + if (values_absolute) \ + plugin_dispatch_multivalue (vl, 0, DS_TYPE_GAUGE, __VA_ARGS__, NULL); \ + if (values_percentage) \ + plugin_dispatch_multivalue (vl, 1, DS_TYPE_GAUGE, __VA_ARGS__, NULL); \ +} while (0) -static int memory_read (void) +static int memory_read_internal (value_list_t *vl) { #if HAVE_HOST_STATISTICS kern_return_t status; @@ -195,7 +182,6 @@ static int memory_read (void) gauge_t active; gauge_t inactive; gauge_t free; - gauge_t total; if (!port_host || !pagesize) return (-1); @@ -233,22 +219,11 @@ static int memory_read (void) 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)); - total = wired + active + inactive + free; - if (values_absolute) - { - memory_submit ("wired", wired); - memory_submit ("active", active); - memory_submit ("inactive", inactive); - memory_submit ("free", free); - } - if (values_percentage) - { - memory_submit ("percent_wired", (gauge_t) ((float_t) wired) / total * 100); - memory_submit ("percent_active", (gauge_t) ((float_t) active) / total * 100); - memory_submit ("percent_inactive", (gauge_t) ((float_t) inactive / total * 100); - memory_submit ("percent_free", (gauge_t) ((float_t) free / total * 100); - } + MEMORY_SUBMIT ("wired", wired, + "active", active, + "inactive", inactive, + "free", free); /* #endif HAVE_HOST_STATISTICS */ #elif HAVE_SYSCTLBYNAME @@ -261,7 +236,7 @@ static int memory_read (void) * vm.stats.vm.v_inactive_count: 113730 * vm.stats.vm.v_cache_count: 10809 */ - char *sysctl_keys[8] = + const char *sysctl_keys[8] = { "vm.stats.vm.v_page_size", "vm.stats.vm.v_page_count", @@ -274,9 +249,7 @@ static int memory_read (void) }; double sysctl_vals[8]; - int i; - - for (i = 0; sysctl_keys[i] != NULL; i++) + for (int i = 0; sysctl_keys[i] != NULL; i++) { int value; size_t value_len = sizeof (value); @@ -294,27 +267,15 @@ static int memory_read (void) } /* for (sysctl_keys) */ /* multiply all all page counts with the pagesize */ - for (i = 1; sysctl_keys[i] != NULL; i++) + for (int i = 1; sysctl_keys[i] != NULL; i++) if (!isnan (sysctl_vals[i])) sysctl_vals[i] *= sysctl_vals[0]; - if (values_absolute) - { - 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]); - } - if (values_percentage) - { - double total = sysctl_vals[2] + sysctl_vals[3] + sysctl_vals[4] + sysctl_vals[5] + sysctl_vals[6]; - memory_submit ("percent_free", (gauge_t) ((float_t) sysctl_vals[2]) / total * 100); - memory_submit ("percent_wired", (gauge_t) ((float_t) sysctl_vals[3]) / total * 100); - memory_submit ("percent_active", (gauge_t) ((float_t) sysctl_vals[4]) / total * 100); - memory_submit ("percent_inactive", (gauge_t) ((float_t) sysctl_vals[5]) / total * 100); - memory_submit ("percent_cache", (gauge_t) ((float_t) sysctl_vals[6]) / total * 100); - } + 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 @@ -324,11 +285,16 @@ static int memory_read (void) char *fields[8]; int numfields; - long long mem_total = 0; - long long mem_used = 0; - long long mem_buffered = 0; - long long mem_cached = 0; - long long mem_free = 0; + _Bool detailed_slab_info = 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; + gauge_t mem_slab_total = 0; + gauge_t mem_slab_reclaimable = 0; + gauge_t mem_slab_unreclaimable = 0; if ((fh = fopen ("/proc/meminfo", "r")) == NULL) { @@ -338,9 +304,9 @@ 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_total; @@ -350,15 +316,24 @@ static int memory_read (void) val = &mem_buffered; else if (strncasecmp (buffer, "Cached:", 7) == 0) val = &mem_cached; + else if (strncasecmp (buffer, "Slab:", 5) == 0) + val = &mem_slab_total; + else if (strncasecmp (buffer, "SReclaimable:", 13) == 0) { + val = &mem_slab_reclaimable; + detailed_slab_info = 1; + } + else if (strncasecmp (buffer, "SUnreclaim:", 11) == 0) { + val = &mem_slab_unreclaimable; + detailed_slab_info = 1; + } 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)) @@ -368,34 +343,40 @@ static int memory_read (void) sstrerror (errno, errbuf, sizeof (errbuf))); } - if (mem_total >= (mem_free + mem_buffered + mem_cached)) - { - mem_used = mem_total - (mem_free + mem_buffered + mem_cached); - if (values_absolute) - { - memory_submit ("used", mem_used); - memory_submit ("buffered", mem_buffered); - memory_submit ("cached", mem_cached); - memory_submit ("free", mem_free); - } - if (values_percentage) - { - memory_submit ("percent_used", (gauge_t) ((float_t) mem_used) / mem_total * 100); - memory_submit ("percent_buffered", (gauge_t) ((float_t) mem_buffered) / mem_total * 100); - memory_submit ("percent_cached", (gauge_t) ((float_t) mem_cached) / mem_total * 100); - memory_submit ("percent_free", (gauge_t) ((float_t) mem_free) / mem_total * 100); - } - } + if (mem_total < (mem_free + mem_buffered + mem_cached + mem_slab_total)) + return (-1); + + mem_used = mem_total - (mem_free + mem_buffered + mem_cached + mem_slab_total); + + /* SReclaimable and SUnreclaim were introduced in kernel 2.6.19 + * They sum up to the value of Slab, which is available on older & newer + * kernels. So SReclaimable/SUnreclaim are submitted if available, and Slab + * if not. */ + if (detailed_slab_info) + MEMORY_SUBMIT ("used", mem_used, + "buffered", mem_buffered, + "cached", mem_cached, + "free", mem_free, + "slab_unrecl", mem_slab_unreclaimable, + "slab_recl", mem_slab_reclaimable); + else + MEMORY_SUBMIT ("used", mem_used, + "buffered", mem_buffered, + "cached", mem_cached, + "free", mem_free, + "slab", mem_slab_total); /* #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 */ + /* 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 arcsize; + long long pp_kernel; long long physmem; @@ -403,17 +384,20 @@ static int memory_read (void) if (ksp == NULL) return (-1); + if (ksz == NULL) + return (-1); 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; - + arcsize = get_kstat_value (ksz, "size"); pp_kernel = get_kstat_value (ksp, "pp_kernel"); physmem = get_kstat_value (ksp, "physmem"); availrmem = get_kstat_value (ksp, "availrmem"); + mem_kern = 0; + mem_unus = 0; + if ((mem_used < 0LL) || (mem_free < 0LL) || (mem_lock < 0LL)) { WARNING ("memory plugin: one of used, free or locked is negative."); @@ -440,7 +424,7 @@ static int memory_read (void) } /* mem_kern is accounted for in mem_lock */ - if ( pp_kernel < mem_lock ) + if (pp_kernel < mem_lock) { mem_kern = pp_kernel; mem_lock -= pp_kernel; @@ -456,32 +440,25 @@ static int memory_read (void) mem_lock *= pagesize; /* some? ;) */ mem_kern *= pagesize; /* it's 2011 RAM is cheap */ mem_unus *= pagesize; + mem_kern -= arcsize; - if (values_absolute) - { - memory_submit ("used", mem_used); - memory_submit ("free", mem_free); - memory_submit ("locked", mem_lock); - memory_submit ("kernel", mem_kern); - memory_submit ("unusable", mem_unus); - } - if (values_percentage) - { - memory_submit ("percent_used", (gauge_t) ((float_t) mem_used) / (mem_used + mem_free + mem_lock + mem_kern + mem_unus) * 100); - memory_submit ("percent_free", (gauge_t) ((float_t) mem_free) / (mem_used + mem_free + mem_lock + mem_kern + mem_unus) * 100); - memory_submit ("percent_locked", (gauge_t) ((float_t) mem_lock) / (mem_used + mem_free + mem_lock + mem_kern + mem_unus) * 100); - memory_submit ("percent_kernel", (gauge_t) ((float_t) mem_kern) / (mem_used + mem_free + mem_lock + mem_kern + mem_unus) * 100); - memory_submit ("percent_unusable", (gauge_t) ((float_t) mem_unus) / (mem_used + mem_free + mem_lock + mem_kern + mem_unus) * 100); - } + MEMORY_SUBMIT ("used", (gauge_t) mem_used, + "free", (gauge_t) mem_free, + "locked", (gauge_t) mem_lock, + "kernel", (gauge_t) mem_kern, + "arc", (gauge_t) arcsize, + "unusable", (gauge_t) mem_unus); /* #endif HAVE_LIBKSTAT */ #elif HAVE_SYSCTL int mib[] = {CTL_VM, VM_METER}; - struct vmtotal vmtotal; + struct vmtotal vmtotal = { 0 }; + gauge_t mem_active; + gauge_t mem_inactive; + gauge_t mem_free; size_t size; - memset (&vmtotal, 0, sizeof (vmtotal)); size = sizeof (vmtotal); if (sysctl (mib, 2, &vmtotal, &size, NULL, 0) < 0) { @@ -492,73 +469,75 @@ static int memory_read (void) } assert (pagesize > 0); - if (values_absolute) - { - memory_submit ("active", vmtotal.t_arm * pagesize); - memory_submit ("inactive", (vmtotal.t_rm - vmtotal.t_arm) * pagesize); - memory_submit ("free", vmtotal.t_free * pagesize); - } - if (values_percentage) - { - memory_submit ("percent_active", (gauge_t) ((float_t) vmtotal.t_arm) / (vmtotal.t_rm + vmtotal.t_free) * 100); - memory_submit ("percent_inactive", (gauge_t) ((float_t) (vmtotal.t_rm - vmtotal.t_arm) / (vmtotal.t_rm + vmtotal.t_free) * 100); - memory_submit ("percent_free", (gauge_t) ((float_t) vmtotal.t_free) / (vmtotal.t_rm + vmtotal.t_free) * 100); - } + 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) - { - if (values_absolute) - { - memory_submit ("used", ios->used); - memory_submit ("cached", ios->cache); - memory_submit ("free", ios->free); - } - if (values_percentage) - { - memory_submit ("percent_used", (gauge_t) ((float_t) ios->used) / (ios->used + ios->cache + ios->free) * 100); - memory_submit ("percent_cached", (gauge_t) ((float_t) ios->cache) / (ios->used + ios->cache + ios->free) * 100); - memory_submit ("percent_free", (gauge_t) ((float_t) ios->free) / (ios->used + ios->cache + ios->free) * 100); - } - } + 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 - if (perfstat_memory_total(NULL, &pmemory, sizeof(perfstat_memory_total_t), 1) < 0) + perfstat_memory_total_t pmemory = { 0 }; + + if (perfstat_memory_total(NULL, &pmemory, sizeof(pmemory), 1) < 0) { char errbuf[1024]; WARNING ("memory plugin: perfstat_memory_total failed: %s", sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); } - if (values_absolute) - { - memory_submit ("used", pmemory.real_inuse * pagesize); - memory_submit ("free", pmemory.real_free * pagesize); - memory_submit ("cached", pmemory.numperm * pagesize); - memory_submit ("system", pmemory.real_system * pagesize); - memory_submit ("user", pmemory.real_process * pagesize); - } - if (values_percentage) - { - memory_submit ("percent_used", (gauge_t) ((float_t) pmemory.real_inuse) / pmemory.real_total * 100); - memory_submit ("percent_free", (gauge_t) ((float_t) pmemory.real_free) / pmemory.real_total * 100); - memory_submit ("percent_cached", (gauge_t) ((float_t) pmemory.numperm) / pmemory.real_total * 100); - memory_submit ("percent_system", (gauge_t) ((float_t) pmemory.real_system) / pmemory.real_total * 100); - memory_submit ("percent_user", (gauge_t) ((float_t) pmemory.real_process) / pmemory.real_total * 100); - } + + /* 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_config ("memory", memory_config, - config_keys, config_keys_num); + plugin_register_complex_config ("memory", memory_config); plugin_register_init ("memory", memory_init); plugin_register_read ("memory", memory_read); } /* void module_register */