diff options
Diffstat (limited to 'src/pmdas/linux/proc_cpuinfo.c')
-rw-r--r-- | src/pmdas/linux/proc_cpuinfo.c | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/src/pmdas/linux/proc_cpuinfo.c b/src/pmdas/linux/proc_cpuinfo.c new file mode 100644 index 0000000..f76ac27 --- /dev/null +++ b/src/pmdas/linux/proc_cpuinfo.c @@ -0,0 +1,246 @@ +/* + * Linux /proc/cpuinfo metrics cluster + * + * Copyright (c) 2013-2014 Red Hat. + * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + * Portions Copyright (c) 2001 Gilly Ran (gilly@exanet.com) - for the + * portions supporting the Alpha platform. All rights reserved. + * + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <ctype.h> +#include <dirent.h> +#include <sys/stat.h> +#include "pmapi.h" +#include "impl.h" +#include "pmda.h" +#include "indom.h" +#include "proc_cpuinfo.h" + + +static void +decode_map(proc_cpuinfo_t *proc_cpuinfo, char *cp, int node, int offset) +{ + uint32_t map = strtoul(cp, NULL, 16); + + while (map) { + int i; + + if ((i = ffsl(map))) { + /* the kernel returns 32bit words in the map file */ + int cpu = i - 1 + 32*offset; + + proc_cpuinfo->cpuinfo[cpu].node = node; + if (pmDebug & DBG_TRACE_APPL2) { + fprintf(stderr, "cpu %d -> node %d\n", + cpu, node); + } + map &= ~(1 << (i-1)); + } + } +} + +static void +map_cpu_nodes(proc_cpuinfo_t *proc_cpuinfo) +{ + int i, j; + const char *node_path = "sys/devices/system/node"; + char path[MAXPATHLEN]; + char cpumap[4096]; + DIR *nodes; + FILE *f; + struct dirent *de; + int node, max_node = -1; + char *cp; + pmdaIndom *idp = PMDAINDOM(NODE_INDOM); + + for (i = 0; i < proc_cpuinfo->cpuindom->it_numinst; i++) + proc_cpuinfo->cpuinfo[i].node = -1; + + snprintf(path, sizeof(path), "%s/%s", linux_statspath, node_path); + if ((nodes = opendir(path)) == NULL) + return; + + while ((de = readdir(nodes)) != NULL) { + if (sscanf(de->d_name, "node%d", &node) != 1) + continue; + + if (node > max_node) + max_node = node; + + snprintf(path, sizeof(path), "%s/%s/%s/cpumap", + linux_statspath, node_path, de->d_name); + if ((f = fopen(path, "r")) == NULL) + continue; + i = fscanf(f, "%s", cpumap); + fclose(f); + if (i != 1) + continue; + + for (j = 0; (cp = strrchr(cpumap, ',')); j++) { + decode_map(proc_cpuinfo, cp+1, node, j); + *cp = '\0'; + } + decode_map(proc_cpuinfo, cpumap, node, j); + } + closedir(nodes); + + /* initialize node indom */ + idp->it_numinst = max_node + 1; + idp->it_set = calloc(max_node + 1, sizeof(pmdaInstid)); + for (i = 0; i <= max_node; i++) { + char node_name[256]; + + sprintf(node_name, "node%d", i); + idp->it_set[i].i_inst = i; + idp->it_set[i].i_name = strdup(node_name); + } + proc_cpuinfo->node_indom = idp; +} + +char * +cpu_name(proc_cpuinfo_t *proc_cpuinfo, int c) +{ + char name[1024]; + char *p; + FILE *f; + static int started = 0; + + if (!started) { + refresh_proc_cpuinfo(proc_cpuinfo); + + proc_cpuinfo->machine = NULL; + f = linux_statsfile("/proc/sgi_prominfo/node0/version", name, sizeof(name)); + if (f != NULL) { + while (fgets(name, sizeof(name), f)) { + if (strncmp(name, "SGI", 3) == 0) { + if ((p = strstr(name, " IP")) != NULL) + proc_cpuinfo->machine = strndup(p+1, 4); + break; + } + } + fclose(f); + } + if (proc_cpuinfo->machine == NULL) + proc_cpuinfo->machine = strdup("linux"); + + started = 1; + } + + snprintf(name, sizeof(name), "cpu%d", c); + return strdup(name); +} + +int +refresh_proc_cpuinfo(proc_cpuinfo_t *proc_cpuinfo) +{ + char buf[4096]; + FILE *fp; + int cpunum; + cpuinfo_t *info; + char *val; + char *p; + static int started = 0; + + if (!started) { + int need = proc_cpuinfo->cpuindom->it_numinst * sizeof(cpuinfo_t); + proc_cpuinfo->cpuinfo = (cpuinfo_t *)calloc(1, need); + for (cpunum=0; cpunum < proc_cpuinfo->cpuindom->it_numinst; cpunum++) { + proc_cpuinfo->cpuinfo[cpunum].sapic = -1; + proc_cpuinfo->cpuinfo[cpunum].vendor = -1; + proc_cpuinfo->cpuinfo[cpunum].model = -1; + proc_cpuinfo->cpuinfo[cpunum].model_name = -1; + proc_cpuinfo->cpuinfo[cpunum].stepping = -1; + proc_cpuinfo->cpuinfo[cpunum].flags = -1; + } + started = 1; + } + + if ((fp = linux_statsfile("/proc/cpuinfo", buf, sizeof(buf))) == NULL) + return -oserror(); + +#if defined(HAVE_ALPHA_LINUX) + cpunum = 0; +#else //intel + cpunum = -1; +#endif + while (fgets(buf, sizeof(buf), fp) != NULL) { + if ((val = strrchr(buf, '\n')) != NULL) + *val = '\0'; + if ((val = strchr(buf, ':')) == NULL) + continue; + val += 2; + +#if !defined(HAVE_ALPHA_LINUX) + if (strncmp(buf, "processor", 9) == 0) { + cpunum++; + proc_cpuinfo->cpuinfo[cpunum].cpu_num = atoi(val); + continue; + } +#endif + + if (cpunum < 0 || cpunum >= proc_cpuinfo->cpuindom->it_numinst) + continue; + + info = &proc_cpuinfo->cpuinfo[cpunum]; + + /* note: order is important due to strNcmp comparisons */ + if (info->sapic < 0 && strncasecmp(buf, "sapic", 5) == 0) + info->sapic = linux_strings_insert(val); + else if (info->model_name < 0 && strncasecmp(buf, "model name", 10) == 0) + info->model_name = linux_strings_insert(val); + else if (info->model < 0 && strncasecmp(buf, "model", 5) == 0) + info->model = linux_strings_insert(val); + else if (info->model < 0 && strncasecmp(buf, "cpu model", 9) == 0) + info->model = linux_strings_insert(val); + else if (info->vendor < 0 && strncasecmp(buf, "vendor", 6) == 0) + info->vendor = linux_strings_insert(val); + else if (info->stepping < 0 && strncasecmp(buf, "step", 4) == 0) + info->stepping = linux_strings_insert(val); + else if (info->stepping < 0 && strncasecmp(buf, "revision", 8) == 0) + info->stepping = linux_strings_insert(val); + else if (info->stepping < 0 && strncasecmp(buf, "cpu revision", 12) == 0) + info->stepping = linux_strings_insert(val); + else if (info->flags < 0 && strncasecmp(buf, "flags", 5) == 0) + info->flags = linux_strings_insert(val); + else if (info->flags < 0 && strncasecmp(buf, "features", 8) == 0) + info->flags = linux_strings_insert(val); + else if (info->cache == 0 && strncasecmp(buf, "cache size", 10) == 0) + info->cache = atoi(val); + else if (info->cache_align == 0 && strncasecmp(buf, "cache_align", 11) == 0) + info->cache_align = atoi(val); + else if (info->bogomips == 0.0 && strncasecmp(buf, "bogo", 4) == 0) + info->bogomips = atof(val); + else if (info->clock == 0.0 && strncasecmp(buf, "cpu MHz", 7) == 0) + info->clock = atof(val); + else if (info->clock == 0.0 && strncasecmp(buf, "cycle frequency", 15) == 0) { + if ((p = strchr(val, ' ')) != NULL) + *p = '\0'; + info->clock = (atof(val))/1000000; + } + } + fclose(fp); + +#if defined(HAVE_ALPHA_LINUX) + /* all processors are identical, therefore duplicate it to all the instances */ + for (cpunum = 1; cpunum < proc_cpuinfo->cpuindom->it_numinst; cpunum++) + memcpy(&proc_cpuinfo->cpuinfo[cpunum], info, sizeof(cpuinfo_t)); +#endif + + if (started < 2) { + map_cpu_nodes(proc_cpuinfo); + started = 2; + } + + /* success */ + return 0; +} |