/** * collectd - src/mic.c * Copyright (C) 2013 Battelle Memorial Institute * * 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; only version 2 of the License is applicable. * * 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. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Authors: * Evan Felix **/ #include "collectd.h" #include "plugin.h" #include "utils/common/common.h" #include "utils/ignorelist/ignorelist.h" #include #include #include #include #include #define MAX_MICS 32 #define MAX_CORES 256 static MicDeviceOnSystem mics[MAX_MICS]; static U32 num_mics; static HANDLE mic_handle; static int const therm_ids[] = { eMicThermalDie, eMicThermalDevMem, eMicThermalFin, eMicThermalFout, eMicThermalVccp, eMicThermalVddg, eMicThermalVddq}; static char const *const therm_names[] = {"die", "devmem", "fin", "fout", "vccp", "vddg", "vddq"}; static const char *config_keys[] = { "ShowCPU", "ShowCPUCores", "ShowMemory", "ShowTemperatures", "Temperature", "IgnoreSelectedTemperature", "ShowPower", "Power", "IgnoreSelectedPower"}; static int config_keys_num = STATIC_ARRAY_SIZE(config_keys); static bool show_cpu = true; static bool show_cpu_cores = true; static bool show_memory = true; static bool show_temps = true; static ignorelist_t *temp_ignore; static bool show_power = true; static ignorelist_t *power_ignore; static int mic_init(void) { U32 ret; U32 mic_count; if (mic_handle) return 0; mic_count = (U32)STATIC_ARRAY_SIZE(mics); ret = MicInitAPI(&mic_handle, eTARGET_SCIF_DRIVER, mics, &mic_count); if (ret != MIC_ACCESS_API_SUCCESS) { ERROR("mic plugin: Problem initializing MicAccessAPI: %s", MicGetErrorString(ret)); } DEBUG("mic plugin: found: %" PRIu32 " MIC(s)", mic_count); if (mic_count < 0 || mic_count >= MAX_MICS) { ERROR("mic plugin: No Intel MICs in system"); return 1; } else { num_mics = mic_count; return 0; } } static int mic_config(const char *key, const char *value) { if (temp_ignore == NULL) temp_ignore = ignorelist_create(1); if (power_ignore == NULL) power_ignore = ignorelist_create(1); if (temp_ignore == NULL || power_ignore == NULL) return 1; if (strcasecmp("ShowCPU", key) == 0) { show_cpu = IS_TRUE(value); } else if (strcasecmp("ShowCPUCores", key) == 0) { show_cpu_cores = IS_TRUE(value); } else if (strcasecmp("ShowTemperatures", key) == 0) { show_temps = IS_TRUE(value); } else if (strcasecmp("ShowMemory", key) == 0) { show_memory = IS_TRUE(value); } else if (strcasecmp("ShowPower", key) == 0) { show_power = IS_TRUE(value); } else if (strcasecmp("Temperature", key) == 0) { ignorelist_add(temp_ignore, value); } else if (strcasecmp("IgnoreSelectedTemperature", key) == 0) { int invert = 1; if (IS_TRUE(value)) invert = 0; ignorelist_set_invert(temp_ignore, invert); } else if (strcasecmp("Power", key) == 0) { ignorelist_add(power_ignore, value); } else if (strcasecmp("IgnoreSelectedPower", key) == 0) { int invert = 1; if (IS_TRUE(value)) invert = 0; ignorelist_set_invert(power_ignore, invert); } else { return -1; } return 0; } static void mic_submit_memory_use(int micnumber, const char *type_instance, U32 value) { value_list_t vl = VALUE_LIST_INIT; /* MicAccessAPI reports KB's of memory, adjust for this */ DEBUG("mic plugin: Memory Value Report; %u %lf", value, ((gauge_t)value) * 1024.0); vl.values = &(value_t){.gauge = ((gauge_t)value) * 1024.0}; vl.values_len = 1; strncpy(vl.plugin, "mic", sizeof(vl.plugin)); ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber); strncpy(vl.type, "memory", sizeof(vl.type)); strncpy(vl.type_instance, type_instance, sizeof(vl.type_instance)); plugin_dispatch_values(&vl); } /* Gather memory Utilization */ static int mic_read_memory(int mic) { U32 ret; U32 mem_total, mem_free, mem_bufs; ret = MicGetMemoryUtilization(mic_handle, &mem_total, &mem_free, &mem_bufs); if (ret != MIC_ACCESS_API_SUCCESS) { ERROR("mic plugin: Problem getting Memory Utilization: %s", MicGetErrorString(ret)); return 1; } mic_submit_memory_use(mic, "free", mem_free); mic_submit_memory_use(mic, "used", mem_total - mem_free - mem_bufs); mic_submit_memory_use(mic, "buffered", mem_bufs); DEBUG("mic plugin: Memory Read: %u %u %u", mem_total, mem_free, mem_bufs); return 0; } static void mic_submit_temp(int micnumber, const char *type, gauge_t value) { value_list_t vl = VALUE_LIST_INIT; vl.values = &(value_t){.gauge = value}; vl.values_len = 1; strncpy(vl.plugin, "mic", sizeof(vl.plugin)); ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber); strncpy(vl.type, "temperature", sizeof(vl.type)); strncpy(vl.type_instance, type, sizeof(vl.type_instance)); plugin_dispatch_values(&vl); } /* Gather Temperature Information */ static int mic_read_temps(int mic) { size_t num_therms = STATIC_ARRAY_SIZE(therm_ids); for (size_t j = 0; j < num_therms; j++) { U32 status; U32 temp_buffer; U32 buffer_size = (U32)sizeof(temp_buffer); char const *name = therm_names[j]; if (ignorelist_match(temp_ignore, name) != 0) continue; status = MicGetTemperature(mic_handle, therm_ids[j], &temp_buffer, &buffer_size); if (status != MIC_ACCESS_API_SUCCESS) { ERROR("mic plugin: Error reading temperature \"%s\": " "%s", name, MicGetErrorString(status)); return 1; } mic_submit_temp(mic, name, temp_buffer); } return 0; } static void mic_submit_cpu(int micnumber, const char *type_instance, int core, derive_t value) { value_list_t vl = VALUE_LIST_INIT; vl.values = &(value_t){.derive = value}; vl.values_len = 1; strncpy(vl.plugin, "mic", sizeof(vl.plugin)); if (core < 0) /* global aggregation */ ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber); else /* per-core statistics */ ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i-cpu-%i", micnumber, core); strncpy(vl.type, "cpu", sizeof(vl.type)); strncpy(vl.type_instance, type_instance, sizeof(vl.type_instance)); plugin_dispatch_values(&vl); } /*Gather CPU Utilization Information */ static int mic_read_cpu(int mic) { MicCoreUtil core_util; MicCoreJiff core_jiffs[MAX_CORES]; U32 core_jiffs_size; U32 status; core_jiffs_size = MAX_CORES * sizeof(MicCoreJiff); status = MicGetCoreUtilization(mic_handle, &core_util, core_jiffs, &core_jiffs_size); if (status != MIC_ACCESS_API_SUCCESS) { ERROR("mic plugin: Problem getting CPU utilization: %s", MicGetErrorString(status)); return -1; } if (show_cpu) { mic_submit_cpu(mic, "user", -1, core_util.sum.user); mic_submit_cpu(mic, "sys", -1, core_util.sum.sys); mic_submit_cpu(mic, "nice", -1, core_util.sum.nice); mic_submit_cpu(mic, "idle", -1, core_util.sum.idle); } if (show_cpu_cores) { for (int j = 0; j < core_util.core; j++) { mic_submit_cpu(mic, "user", j, core_jiffs[j].user); mic_submit_cpu(mic, "sys", j, core_jiffs[j].sys); mic_submit_cpu(mic, "nice", j, core_jiffs[j].nice); mic_submit_cpu(mic, "idle", j, core_jiffs[j].idle); } } return 0; } static void mic_submit_power(int micnumber, const char *type, const char *type_instance, gauge_t value) { value_list_t vl = VALUE_LIST_INIT; vl.values = &(value_t){.gauge = value}; vl.values_len = 1; strncpy(vl.plugin, "mic", sizeof(vl.plugin)); ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber); strncpy(vl.type, type, sizeof(vl.type)); strncpy(vl.type_instance, type_instance, sizeof(vl.type_instance)); plugin_dispatch_values(&vl); } /* Gather Power Information */ static int mic_read_power(int mic) { U32 ret; MicPwrUsage power_use; ret = MicGetPowerUsage(mic_handle, &power_use); if (ret != MIC_ACCESS_API_SUCCESS) { ERROR("mic plugin: Problem getting Power Usage: %s", MicGetErrorString(ret)); return 1; } /* power is in uWatts, current in mA, voltage in uVolts.. convert to * base unit */ #define SUB_POWER(name) \ do { \ if (ignorelist_match(power_ignore, #name) == 0) \ mic_submit_power(mic, "power", #name, \ (gauge_t)power_use.name.prr * 0.000001); \ } while (0) #define SUB_VOLTS(name) \ do { \ if (ignorelist_match(power_ignore, #name) == 0) { \ mic_submit_power(mic, "power", #name, \ (gauge_t)(power_use.name.pwr * 0.000001)); \ mic_submit_power(mic, "current", #name, \ (gauge_t)(power_use.name.cur * 0.001)); \ mic_submit_power(mic, "voltage", #name, \ (gauge_t)(power_use.name.volt * 0.000001)); \ } \ } while (0) SUB_POWER(total0); SUB_POWER(total1); SUB_POWER(inst); SUB_POWER(imax); SUB_POWER(pcie); SUB_POWER(c2x3); SUB_POWER(c2x4); SUB_VOLTS(vccp); SUB_VOLTS(vddg); SUB_VOLTS(vddq); return 0; } static int mic_read(void) { U32 ret; int error; error = 0; for (int i = 0; i < num_mics; i++) { ret = MicInitAdapter(&mic_handle, &mics[i]); if (ret != MIC_ACCESS_API_SUCCESS) { ERROR("mic plugin: Problem initializing MicAdapter: %s", MicGetErrorString(ret)); error = 1; } if (error == 0 && show_memory) error = mic_read_memory(i); if (error == 0 && show_temps) error = mic_read_temps(i); if (error == 0 && (show_cpu || show_cpu_cores)) error = mic_read_cpu(i); if (error == 0 && (show_power)) error = mic_read_power(i); ret = MicCloseAdapter(mic_handle); if (ret != MIC_ACCESS_API_SUCCESS) { ERROR("mic plugin: Problem closing MicAdapter: %s", MicGetErrorString(ret)); error = 2; break; } } if (num_mics == 0) error = 3; return error; } static int mic_shutdown(void) { if (mic_handle) MicCloseAPI(&mic_handle); mic_handle = NULL; return 0; } void module_register(void) { plugin_register_init("mic", mic_init); plugin_register_shutdown("mic", mic_shutdown); plugin_register_read("mic", mic_read); plugin_register_config("mic", mic_config, config_keys, config_keys_num); } /* void module_register */