X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fzfs_arc.c;h=aff02b62ccc390a6d000f355063f39f59c701bc2;hp=8feb31d55c0bfc75f571e0398edfef965e8fcc78;hb=7111bb6df7628edce3a8e538b386fbe27633a191;hpb=e2b289ea039269b60edd459d2d514d3f82820e3a diff --git a/src/zfs_arc.c b/src/zfs_arc.c index 8feb31d5..6c66fb13 100644 --- a/src/zfs_arc.c +++ b/src/zfs_arc.c @@ -28,45 +28,91 @@ **/ #include "collectd.h" + #include "common.h" #include "plugin.h" /* * Global variables */ +static value_to_rate_state_t arc_hits_state; +static value_to_rate_state_t arc_misses_state; +static value_to_rate_state_t l2_hits_state; +static value_to_rate_state_t l2_misses_state; #if defined(KERNEL_LINUX) #include "utils_llist.h" #define ZOL_ARCSTATS_FILE "/proc/spl/kstat/zfs/arcstats" -typedef llist_t kstat_t; +typedef llist_t kstat_t; -static long long get_zfs_value(kstat_t *zfs_stats __attribute__((unused)), - char *name) -{ - llentry_t *e; +static int put_zfs_value(kstat_t *ksp, char const *k, value_t v) { + llentry_t *e; + char *k_copy; + value_t *v_copy; + + k_copy = strdup(k); + if (k_copy == NULL) + return ENOMEM; + + v_copy = malloc(sizeof(*v_copy)); + if (v_copy == NULL) { + sfree(k_copy); + return ENOMEM; + } + *v_copy = v; + + e = llentry_create(k_copy, v_copy); + if (e == NULL) { + sfree(v_copy); + sfree(k_copy); + return ENOMEM; + } + + llist_append(ksp, e); + return 0; +} + +static long long get_zfs_value(kstat_t *ksp, const char *key) { + llentry_t *e; + value_t *v; + + e = llist_search(ksp, key); + if (e == NULL) { + return -1; + } + + v = e->value; + return (long long)v->derive; +} + +static void free_zfs_values(kstat_t *ksp) { + if (ksp == NULL) + return; - e = llist_search (zfs_stats, name); - if (e == NULL) - { - ERROR ("zfs_arc plugin: `llist_search` failed for key: '%s'.", name); - return (-1); - } + for (llentry_t *e = llist_head(ksp); e != NULL; e = e->next) { + sfree(e->key); + sfree(e->value); + } - return (*(long long int*)e->value); + llist_destroy(ksp); } -#elif !defined(__FreeBSD__) // Solaris +#elif defined(KERNEL_SOLARIS) + +#if HAVE_KSTAT_H +#include +#endif + extern kstat_ctl_t *kc; -static long long get_zfs_value(kstat_t *ksp, char *name) -{ +static long long get_zfs_value(kstat_t *ksp, char *name) { - return (get_kstat_value(ksp, name)); + return get_kstat_value(ksp, name); } -#else // FreeBSD -#include +#elif defined(KERNEL_FREEBSD) #include +#include const char zfs_arcstat[] = "kstat.zfs.misc.arcstats."; @@ -75,273 +121,270 @@ typedef void kstat_t; #endif static long long get_zfs_value(kstat_t *dummy __attribute__((unused)), - char const *name) -{ - char buffer[256]; - long long value; - size_t valuelen = sizeof(value); - int rv; - - ssnprintf (buffer, sizeof (buffer), "%s%s", zfs_arcstat, name); - rv = sysctlbyname (buffer, (void *) &value, &valuelen, - /* new value = */ NULL, /* new length = */ (size_t) 0); - if (rv == 0) - return (value); - - return (-1); + char const *name) { + char buffer[256]; + long long value; + size_t valuelen = sizeof(value); + int rv; + + snprintf(buffer, sizeof(buffer), "%s%s", zfs_arcstat, name); + rv = sysctlbyname(buffer, (void *)&value, &valuelen, + /* new value = */ NULL, /* new length = */ (size_t)0); + if (rv == 0) + return value; + + return -1; } #endif -static void za_submit (const char* type, const char* type_instance, value_t* values, int values_len) -{ - value_list_t vl = VALUE_LIST_INIT; +static void za_submit(const char *type, const char *type_instance, + value_t *values, size_t values_len) { + value_list_t vl = VALUE_LIST_INIT; - vl.values = values; - vl.values_len = values_len; + vl.values = values; + vl.values_len = values_len; - sstrncpy (vl.host, hostname_g, sizeof (vl.host)); - sstrncpy (vl.plugin, "zfs_arc", sizeof (vl.plugin)); - sstrncpy (vl.type, type, sizeof (vl.type)); - sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance)); + sstrncpy(vl.plugin, "zfs_arc", sizeof(vl.plugin)); + sstrncpy(vl.type, type, sizeof(vl.type)); + sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance)); - plugin_dispatch_values (&vl); + plugin_dispatch_values(&vl); } -static void za_submit_gauge (const char* type, const char* type_instance, gauge_t value) -{ - value_t vv; - - vv.gauge = value; - za_submit (type, type_instance, &vv, 1); +static void za_submit_gauge(const char *type, const char *type_instance, + gauge_t value) { + za_submit(type, type_instance, &(value_t){.gauge = value}, 1); } -static int za_read_derive (kstat_t *ksp, const char *kstat_value, - const char *type, const char *type_instance) -{ - long long tmp; - value_t v; - - tmp = get_zfs_value (ksp, (char *)kstat_value); - if (tmp == -1LL) - { - WARNING ("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value); - return (-1); +static int za_read_derive(kstat_t *ksp, const char *kstat_value, + const char *type, const char *type_instance) { + long long tmp = get_zfs_value(ksp, (char *)kstat_value); + if (tmp == -1LL) { + DEBUG("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value); + return -1; } - v.derive = (derive_t) tmp; - za_submit (type, type_instance, /* values = */ &v, /* values_num = */ 1); - return (0); + za_submit(type, type_instance, &(value_t){.derive = (derive_t)tmp}, + /* values_num = */ 1); + return 0; } -static int za_read_gauge (kstat_t *ksp, const char *kstat_value, - const char *type, const char *type_instance) -{ - long long tmp; - value_t v; - - tmp = get_zfs_value (ksp, (char *)kstat_value); - if (tmp == -1LL) - { - WARNING ("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value); - return (-1); +static int za_read_gauge(kstat_t *ksp, const char *kstat_value, + const char *type, const char *type_instance) { + long long tmp = get_zfs_value(ksp, (char *)kstat_value); + if (tmp == -1LL) { + DEBUG("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value); + return -1; } - v.gauge = (gauge_t) tmp; - za_submit (type, type_instance, /* values = */ &v, /* values_num = */ 1); - return (0); + za_submit(type, type_instance, &(value_t){.gauge = (gauge_t)tmp}, + /* values_num = */ 1); + return 0; } -static void za_submit_ratio (const char* type_instance, gauge_t hits, gauge_t misses) -{ - gauge_t ratio = NAN; +static void za_submit_ratio(const char *type_instance, gauge_t hits, + gauge_t misses) { + gauge_t ratio = NAN; - if (!isfinite (hits) || (hits < 0.0)) - hits = 0.0; - if (!isfinite (misses) || (misses < 0.0)) - misses = 0.0; + if (!isfinite(hits) || (hits < 0.0)) + hits = 0.0; + if (!isfinite(misses) || (misses < 0.0)) + misses = 0.0; - if ((hits != 0.0) || (misses != 0.0)) - ratio = hits / (hits + misses); + if ((hits != 0.0) || (misses != 0.0)) + ratio = hits / (hits + misses); - za_submit_gauge ("cache_ratio", type_instance, ratio); + za_submit_gauge("cache_ratio", type_instance, ratio); } -static int za_read (void) -{ - gauge_t arc_hits, arc_misses, l2_hits, l2_misses; - value_t l2_io[2]; - kstat_t *ksp = NULL; - -#if KERNEL_LINUX - long long int *llvalues = NULL; - char file_contents[1024 * 10]; - char *fields[3]; - int numfields; - ssize_t len; - - ksp = llist_create (); - if (ksp == NULL) - { - ERROR ("zfs_arc plugin: `llist_create' failed."); - return (-1); - } - - len = read_file_contents (ZOL_ARCSTATS_FILE, file_contents, sizeof(file_contents) - 1); - if (len > 1) - { - - int i=0; - char *pnl = file_contents; - char *pnnl; - - file_contents[len] = '\0'; - - while (pnl != NULL) - { - pnl = strchr(pnl, '\n'); - i++; - if (pnl && (*pnl != '\0')) - pnl++; - } - - if (i > 0) - { - llentry_t *e; - llvalues = malloc(sizeof(long long int) * i); - if (llvalues == NULL) - { - ERROR ("zfs_arc plugin: `malloc' failed."); - llist_destroy (ksp); - return (-1); - } - int j = 0; - - pnl = file_contents; - while (pnl != NULL) - { - pnnl = strchr(pnl, '\n'); - if (pnnl != NULL) - *pnnl = '\0'; - - numfields = strsplit (pnl, fields, 4); - if (numfields == 3) - { - llvalues[j] = atoll (fields[2]); - - e = llentry_create (fields[0], &llvalues[j]); - if (e == NULL) - { - ERROR ("zfs_arc plugin: `llentry_create' failed."); - } - else - { - llist_append (ksp, e); - } - j++; - } - pnl = pnnl; - if (pnl != NULL) - pnl ++; - } - } - } - -#elif !defined(__FreeBSD__) // Solaris - get_kstat (&ksp, "zfs", 0, "arcstats"); - if (ksp == NULL) - { - ERROR ("zfs_arc plugin: Cannot find zfs:0:arcstats kstat."); - return (-1); - } -#endif +static int za_read(void) { + gauge_t arc_hits, arc_misses, l2_hits, l2_misses; + kstat_t *ksp = NULL; - /* Sizes */ - za_read_gauge (ksp, "size", "cache_size", "arc"); - - /* The "l2_size" value has disappeared from Solaris some time in - * early 2013, and has only reappeared recently in Solaris 11.2. - * Stop trying if we ever fail to read it, so we don't spam the log. - */ - static int l2_size_avail = 1; - if (l2_size_avail && za_read_gauge (ksp, "l2_size", "cache_size", "L2") != 0) - l2_size_avail = 0; - - /* Operations */ - za_read_derive (ksp, "deleted", "cache_operation", "deleted"); -#if __FreeBSD__ - za_read_derive (ksp, "allocated","cache_operation", "allocated"); -#if defined(__FreeBSD_version) && (__FreeBSD_version < 1002501) - /* stolen removed from sysctl kstat.zfs.misc.arcstats on FreeBSD 10.2+ */ - za_read_derive (ksp, "stolen", "cache_operation", "stolen"); -#endif -#endif +#if defined(KERNEL_LINUX) + FILE *fh; + char buffer[1024]; + + fh = fopen(ZOL_ARCSTATS_FILE, "r"); + if (fh == NULL) { + char errbuf[1024]; + ERROR("zfs_arc plugin: Opening \"%s\" failed: %s", ZOL_ARCSTATS_FILE, + sstrerror(errno, errbuf, sizeof(errbuf))); + return -1; + } - /* Issue indicators */ - za_read_derive (ksp, "mutex_miss", "mutex_operations", "miss"); - za_read_derive (ksp, "hash_collisions", "hash_collisions", ""); + /* Ignore the first two lines because they contain information about the rest + * of the file. + * See kstat_seq_show_headers module/spl/spl-kstat.c of the spl kernel module. + */ + if ((fgets(buffer, sizeof(buffer), fh) == NULL) || + (fgets(buffer, sizeof(buffer), fh) == NULL)) { + ERROR("zfs_arc plugin: \"%s\" does not contain at least two lines.", + ZOL_ARCSTATS_FILE); + fclose(fh); + return -1; + } - /* Evictions */ - za_read_derive (ksp, "evict_l2_cached", "cache_eviction", "cached"); - za_read_derive (ksp, "evict_l2_eligible", "cache_eviction", "eligible"); - za_read_derive (ksp, "evict_l2_ineligible", "cache_eviction", "ineligible"); + ksp = llist_create(); + if (ksp == NULL) { + ERROR("zfs_arc plugin: `llist_create' failed."); + fclose(fh); + return -1; + } - /* Hits / misses */ - za_read_derive (ksp, "demand_data_hits", "cache_result", "demand_data-hit"); - za_read_derive (ksp, "demand_metadata_hits", "cache_result", "demand_metadata-hit"); - za_read_derive (ksp, "prefetch_data_hits", "cache_result", "prefetch_data-hit"); - za_read_derive (ksp, "prefetch_metadata_hits", "cache_result", "prefetch_metadata-hit"); - za_read_derive (ksp, "demand_data_misses", "cache_result", "demand_data-miss"); - za_read_derive (ksp, "demand_metadata_misses", "cache_result", "demand_metadata-miss"); - za_read_derive (ksp, "prefetch_data_misses", "cache_result", "prefetch_data-miss"); - za_read_derive (ksp, "prefetch_metadata_misses", "cache_result", "prefetch_metadata-miss"); + // Ignore the first two lines because they contain information about + // the rest of the file. + // See kstat_seq_show_headers module/spl/spl-kstat.c of the spl kernel + // module. + if (fgets(buffer, sizeof(buffer), fh) == NULL) { + ERROR("zfs_arc plugin: \"%s\" does not contain a single line.", + ZOL_ARCSTATS_FILE); + fclose(fh); + return (-1); + } + if (fgets(buffer, sizeof(buffer), fh) == NULL) { + ERROR("zfs_arc plugin: \"%s\" does not contain at least two lines.", + ZOL_ARCSTATS_FILE); + fclose(fh); + return (-1); + } - /* Ratios */ - arc_hits = (gauge_t) get_zfs_value(ksp, "hits"); - arc_misses = (gauge_t) get_zfs_value(ksp, "misses"); - l2_hits = (gauge_t) get_zfs_value(ksp, "l2_hits"); - l2_misses = (gauge_t) get_zfs_value(ksp, "l2_misses"); + while (fgets(buffer, sizeof(buffer), fh) != NULL) { + char *fields[3]; + value_t v; + int status; - za_submit_ratio ("arc", arc_hits, arc_misses); - za_submit_ratio ("L2", l2_hits, l2_misses); + status = strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields)); + if (status != 3) + continue; - /* I/O */ - l2_io[0].derive = get_zfs_value(ksp, "l2_read_bytes"); - l2_io[1].derive = get_zfs_value(ksp, "l2_write_bytes"); + status = parse_value(fields[2], &v, DS_TYPE_DERIVE); + if (status != 0) + continue; - za_submit ("io_octets", "L2", l2_io, /* num values = */ 2); + put_zfs_value(ksp, fields[0], v); + } + + fclose(fh); + +#elif defined(KERNEL_SOLARIS) + get_kstat(&ksp, "zfs", 0, "arcstats"); + if (ksp == NULL) { + ERROR("zfs_arc plugin: Cannot find zfs:0:arcstats kstat."); + return -1; + } +#endif + + /* Sizes */ + za_read_gauge(ksp, "anon_size", "cache_size", "anon_size"); + za_read_gauge(ksp, "c", "cache_size", "c"); + za_read_gauge(ksp, "c_max", "cache_size", "c_max"); + za_read_gauge(ksp, "c_min", "cache_size", "c_min"); + za_read_gauge(ksp, "hdr_size", "cache_size", "hdr_size"); + za_read_gauge(ksp, "metadata_size", "cache_size", "metadata_size"); + za_read_gauge(ksp, "mfu_ghost_size", "cache_size", "mfu_ghost_size"); + za_read_gauge(ksp, "mfu_size", "cache_size", "mfu_size"); + za_read_gauge(ksp, "mru_ghost_size", "cache_size", "mru_ghost_size"); + za_read_gauge(ksp, "mru_size", "cache_size", "mru_size"); + za_read_gauge(ksp, "other_size", "cache_size", "other_size"); + za_read_gauge(ksp, "p", "cache_size", "p"); + za_read_gauge(ksp, "size", "cache_size", "arc"); + + /* The "l2_size" value has disappeared from Solaris some time in + * early 2013, and has only reappeared recently in Solaris 11.2. + * Stop trying if we ever fail to read it, so we don't spam the log. + */ + static int l2_size_avail = 1; + if (l2_size_avail && za_read_gauge(ksp, "l2_size", "cache_size", "L2") != 0) + l2_size_avail = 0; + + /* Operations */ + za_read_derive(ksp, "deleted", "cache_operation", "deleted"); +#if defined(KERNEL_FREEBSD) + za_read_derive(ksp, "allocated", "cache_operation", "allocated"); +#endif + + /* Issue indicators */ + za_read_derive(ksp, "mutex_miss", "mutex_operations", "miss"); + za_read_derive(ksp, "hash_collisions", "hash_collisions", ""); + za_read_derive(ksp, "memory_throttle_count", "memory_throttle_count", ""); + + /* Evictions */ + za_read_derive(ksp, "evict_l2_cached", "cache_eviction", "cached"); + za_read_derive(ksp, "evict_l2_eligible", "cache_eviction", "eligible"); + za_read_derive(ksp, "evict_l2_ineligible", "cache_eviction", "ineligible"); + + /* Hits / misses */ + za_read_derive(ksp, "demand_data_hits", "cache_result", "demand_data-hit"); + za_read_derive(ksp, "demand_metadata_hits", "cache_result", + "demand_metadata-hit"); + za_read_derive(ksp, "prefetch_data_hits", "cache_result", + "prefetch_data-hit"); + za_read_derive(ksp, "prefetch_metadata_hits", "cache_result", + "prefetch_metadata-hit"); + za_read_derive(ksp, "demand_data_misses", "cache_result", "demand_data-miss"); + za_read_derive(ksp, "demand_metadata_misses", "cache_result", + "demand_metadata-miss"); + za_read_derive(ksp, "prefetch_data_misses", "cache_result", + "prefetch_data-miss"); + za_read_derive(ksp, "prefetch_metadata_misses", "cache_result", + "prefetch_metadata-miss"); + za_read_derive(ksp, "mfu_hits", "cache_result", "mfu-hit"); + za_read_derive(ksp, "mfu_ghost_hits", "cache_result", "mfu_ghost-hit"); + za_read_derive(ksp, "mru_hits", "cache_result", "mru-hit"); + za_read_derive(ksp, "mru_ghost_hits", "cache_result", "mru_ghost-hit"); + + cdtime_t now = cdtime(); + + /* Ratios */ + if ((value_to_rate(&arc_hits, (value_t){.derive = get_zfs_value(ksp, "hits")}, + DS_TYPE_DERIVE, now, &arc_hits_state) == 0) && + (value_to_rate(&arc_misses, + (value_t){.derive = get_zfs_value(ksp, "misses")}, + DS_TYPE_DERIVE, now, &arc_misses_state) == 0)) { + za_submit_ratio("arc", arc_hits, arc_misses); + } + + if ((value_to_rate(&l2_hits, + (value_t){.derive = get_zfs_value(ksp, "l2_hits")}, + DS_TYPE_DERIVE, now, &l2_hits_state) == 0) && + (value_to_rate(&l2_misses, + (value_t){.derive = get_zfs_value(ksp, "l2_misses")}, + DS_TYPE_DERIVE, now, &l2_misses_state) == 0)) { + za_submit_ratio("L2", l2_hits, l2_misses); + } + + /* I/O */ + value_t l2_io[] = { + {.derive = (derive_t)get_zfs_value(ksp, "l2_read_bytes")}, + {.derive = (derive_t)get_zfs_value(ksp, "l2_write_bytes")}, + }; + za_submit("io_octets", "L2", l2_io, STATIC_ARRAY_SIZE(l2_io)); #if defined(KERNEL_LINUX) - if (llvalues != NULL) - { - free(llvalues); - } - if (ksp != NULL) - { - llist_destroy (ksp); - } + free_zfs_values(ksp); #endif - return (0); + return 0; } /* int za_read */ -static int za_init (void) /* {{{ */ +static int za_init(void) /* {{{ */ { -#if !defined(__FreeBSD__) && !defined(KERNEL_LINUX) // Solaris - /* kstats chain already opened by update_kstat (using *kc), verify everything went fine. */ - if (kc == NULL) - { - ERROR ("zfs_arc plugin: kstat chain control structure not available."); - return (-1); - } +#if defined(KERNEL_SOLARIS) + /* kstats chain already opened by update_kstat (using *kc), verify everything + * went fine. */ + if (kc == NULL) { + ERROR("zfs_arc plugin: kstat chain control structure not available."); + return -1; + } #endif - return (0); + return 0; } /* }}} int za_init */ -void module_register (void) -{ - plugin_register_init ("zfs_arc", za_init); - plugin_register_read ("zfs_arc", za_read); +void module_register(void) { + plugin_register_init("zfs_arc", za_init); + plugin_register_read("zfs_arc", za_read); } /* void module_register */ /* vmi: set sw=8 noexpandtab fdm=marker : */