// SPDX-License-Identifier: GPL-3.0-or-later #include "windows_plugin.h" #include "windows-internals.h" #define _COMMON_PLUGIN_NAME "windows.plugin" #define _COMMON_PLUGIN_MODULE_NAME "PerflibProcesses" #include "../common-contexts/common-contexts.h" struct processor { bool collected_metadata; RRDSET *st; RRDDIM *rd_user; RRDDIM *rd_system; RRDDIM *rd_irq; RRDDIM *rd_dpc; RRDDIM *rd_idle; // RRDSET *st2; // RRDDIM *rd2_busy; COUNTER_DATA percentProcessorTime; COUNTER_DATA percentUserTime; COUNTER_DATA percentPrivilegedTime; COUNTER_DATA percentDPCTime; COUNTER_DATA percentInterruptTime; COUNTER_DATA percentIdleTime; COUNTER_DATA interruptsPerSec; }; struct processor total = { 0 }; void initialize_processor_keys(struct processor *p) { p->percentProcessorTime.key = "% Processor Time"; p->percentUserTime.key = "% User Time"; p->percentPrivilegedTime.key = "% Privileged Time"; p->percentDPCTime.key = "% DPC Time"; p->percentInterruptTime.key = "% Interrupt Time"; p->percentIdleTime.key = "% Idle Time"; p->interruptsPerSec.key = "Interrupts/sec"; } void dict_processor_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) { struct processor *p = value; initialize_processor_keys(p); } static DICTIONARY *processors = NULL; static void initialize(void) { initialize_processor_keys(&total); processors = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct processor)); dictionary_register_insert_callback(processors, dict_processor_insert_cb, NULL); } static bool do_processors(PERF_DATA_BLOCK *pDataBlock, int update_every) { PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "Processor"); if(!pObjectType) return false; static const RRDVAR_ACQUIRED *cpus_var = NULL; int cores_found = 0; uint64_t totalIPC = 0; PERF_INSTANCE_DEFINITION *pi = NULL; for(LONG i = 0; i < pObjectType->NumInstances ; i++) { pi = perflibForEachInstance(pDataBlock, pObjectType, pi); if(!pi) break; if(!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer))) strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1); bool is_total = false; struct processor *p; int cpu = -1; if(strcasecmp(windows_shared_buffer, "_Total") == 0) { p = &total; is_total = true; cpu = -1; } else { p = dictionary_set(processors, windows_shared_buffer, NULL, sizeof(*p)); is_total = false; cpu = str2i(windows_shared_buffer); snprintfz(windows_shared_buffer, sizeof(windows_shared_buffer), "cpu%d", cpu); if(cpu + 1 > cores_found) cores_found = cpu + 1; } if(!is_total && !p->collected_metadata) { // TODO collect processor metadata p->collected_metadata = true; } perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentProcessorTime); perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentUserTime); perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentPrivilegedTime); perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentDPCTime); perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentInterruptTime); perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentIdleTime); perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->interruptsPerSec); if(!p->st) { p->st = rrdset_create_localhost( is_total ? "system" : "cpu" , is_total ? "cpu" : windows_shared_buffer, NULL , is_total ? "cpu" : "utilization" , is_total ? "system.cpu" : "cpu.cpu" , is_total ? "Total CPU Utilization" : "Core Utilization" , "percentage" , PLUGIN_WINDOWS_NAME , "PerflibProcessor" , is_total ? NETDATA_CHART_PRIO_SYSTEM_CPU : NETDATA_CHART_PRIO_CPU_PER_CORE , update_every , RRDSET_TYPE_STACKED ); p->rd_irq = rrddim_add(p->st, "interrupts", "irq", 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); p->rd_user = rrddim_add(p->st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); p->rd_system = rrddim_add(p->st, "privileged", "system", 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); p->rd_dpc = rrddim_add(p->st, "dpc", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); p->rd_idle = rrddim_add(p->st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); rrddim_hide(p->st, "idle"); if(!is_total) rrdlabels_add(p->st->rrdlabels, "cpu", windows_shared_buffer, RRDLABEL_SRC_AUTO); else cpus_var = rrdvar_host_variable_add_and_acquire(localhost, "active_processors"); } uint64_t user = p->percentUserTime.current.Data; uint64_t system = p->percentPrivilegedTime.current.Data; uint64_t dpc = p->percentDPCTime.current.Data; uint64_t irq = p->percentInterruptTime.current.Data; uint64_t idle = p->percentIdleTime.current.Data; totalIPC += p->interruptsPerSec.current.Data; rrddim_set_by_pointer(p->st, p->rd_user, (collected_number)user); rrddim_set_by_pointer(p->st, p->rd_system, (collected_number)system); rrddim_set_by_pointer(p->st, p->rd_irq, (collected_number)irq); rrddim_set_by_pointer(p->st, p->rd_dpc, (collected_number)dpc); rrddim_set_by_pointer(p->st, p->rd_idle, (collected_number)idle); rrdset_done(p->st); // if(!p->st2) { // p->st2 = rrdset_create_localhost( // is_total ? "system" : "cpu2" // , is_total ? "cpu3" : buffer // , NULL // , is_total ? "utilization" : buffer // , is_total ? "system.cpu3" : "cpu2.cpu" // , is_total ? "Total CPU Utilization" : "Core Utilization" // , "percentage" // , PLUGIN_WINDOWS_NAME // , "PerflibProcessor" // , is_total ? NETDATA_CHART_PRIO_SYSTEM_CPU : NETDATA_CHART_PRIO_CPU_PER_CORE // , update_every // , RRDSET_TYPE_STACKED // ); // // p->rd2_busy = perflib_rrddim_add(p->st2, "busy", NULL, 1, 1, &p->percentProcessorTime); // rrddim_hide(p->st2, "idle"); // // if(!is_total) // rrdlabels_add(p->st->rrdlabels, "cpu", buffer, RRDLABEL_SRC_AUTO); // } // // perflib_rrddim_set_by_pointer(p->st2, p->rd2_busy, &p->percentProcessorTime); // rrdset_done(p->st2); } if(cpus_var) rrdvar_host_variable_set(localhost, cpus_var, cores_found); common_interrupts(totalIPC, update_every, NULL); return true; } int do_PerflibProcessor(int update_every, usec_t dt __maybe_unused) { static bool initialized = false; if(unlikely(!initialized)) { initialize(); initialized = true; } DWORD id = RegistryFindIDByName("Processor"); if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND) return -1; PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id); if(!pDataBlock) return -1; do_processors(pDataBlock, update_every); return 0; }