master
c 212 lines 7.7 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "windows_plugin.h"
4 #include "windows-internals.h"
5
6 #define _COMMON_PLUGIN_NAME "windows.plugin"
7 #define _COMMON_PLUGIN_MODULE_NAME "PerflibProcesses"
8 #include "../common-contexts/common-contexts.h"
9
10 struct processor {
11 bool collected_metadata;
12
13 RRDSET *st;
14 RRDDIM *rd_user;
15 RRDDIM *rd_system;
16 RRDDIM *rd_irq;
17 RRDDIM *rd_dpc;
18 RRDDIM *rd_idle;
19
20 // RRDSET *st2;
21 // RRDDIM *rd2_busy;
22
23 COUNTER_DATA percentProcessorTime;
24 COUNTER_DATA percentUserTime;
25 COUNTER_DATA percentPrivilegedTime;
26 COUNTER_DATA percentDPCTime;
27 COUNTER_DATA percentInterruptTime;
28 COUNTER_DATA percentIdleTime;
29
30 COUNTER_DATA interruptsPerSec;
31 };
32
33 struct processor total = {0};
34
35 void initialize_processor_keys(struct processor *p)
36 {
37 p->percentProcessorTime.key = "% Processor Time";
38 p->percentUserTime.key = "% User Time";
39 p->percentPrivilegedTime.key = "% Privileged Time";
40 p->percentDPCTime.key = "% DPC Time";
41 p->percentInterruptTime.key = "% Interrupt Time";
42 p->percentIdleTime.key = "% Idle Time";
43 p->interruptsPerSec.key = "Interrupts/sec";
44 }
45
46 void dict_processor_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
47 {
48 struct processor *p = value;
49 initialize_processor_keys(p);
50 }
51
52 static DICTIONARY *processors = NULL;
53
54 static void initialize(void)
55 {
56 initialize_processor_keys(&total);
57
58 processors = dictionary_create_advanced(
59 DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct processor));
60
61 dictionary_register_insert_callback(processors, dict_processor_insert_cb, NULL);
62 }
63
64 static bool do_processors(PERF_DATA_BLOCK *pDataBlock, int update_every)
65 {
66 PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "Processor");
67 if (!pObjectType)
68 return false;
69
70 static const RRDVAR_ACQUIRED *cpus_var = NULL;
71 int cores_found = 0;
72 uint64_t totalIPC = 0;
73
74 PERF_INSTANCE_DEFINITION *pi = NULL;
75 for (LONG i = 0; i < pObjectType->NumInstances; i++) {
76 pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
77 if (!pi)
78 break;
79
80 if (!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
81 strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
82
83 bool is_total = false;
84 struct processor *p;
85 int cpu = -1;
86 if (strcasecmp(windows_shared_buffer, "_Total") == 0) {
87 p = &total;
88 is_total = true;
89 cpu = -1;
90 } else {
91 p = dictionary_set(processors, windows_shared_buffer, NULL, sizeof(*p));
92 is_total = false;
93 cpu = str2i(windows_shared_buffer);
94 snprintfz(windows_shared_buffer, sizeof(windows_shared_buffer), "cpu%d", cpu);
95
96 if (cpu + 1 > cores_found)
97 cores_found = cpu + 1;
98 }
99
100 if (!is_total && !p->collected_metadata) {
101 // TODO collect processor metadata
102 p->collected_metadata = true;
103 }
104
105 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentProcessorTime);
106 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentUserTime);
107 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentPrivilegedTime);
108 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentDPCTime);
109 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentInterruptTime);
110 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentIdleTime);
111
112 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->interruptsPerSec);
113
114 if (!p->st) {
115 p->st = rrdset_create_localhost(
116 is_total ? "system" : "cpu",
117 is_total ? "cpu" : windows_shared_buffer,
118 NULL,
119 is_total ? "cpu" : "utilization",
120 is_total ? "system.cpu" : "cpu.cpu",
121 is_total ? "Total CPU Utilization" : "Core Utilization",
122 "percentage",
123 PLUGIN_WINDOWS_NAME,
124 "PerflibProcessor",
125 is_total ? NETDATA_CHART_PRIO_SYSTEM_CPU : NETDATA_CHART_PRIO_CPU_PER_CORE,
126 update_every,
127 RRDSET_TYPE_STACKED);
128
129 p->rd_irq = rrddim_add(p->st, "interrupts", "irq", 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
130 p->rd_user = rrddim_add(p->st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
131 p->rd_system = rrddim_add(p->st, "privileged", "system", 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
132 p->rd_dpc = rrddim_add(p->st, "dpc", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
133 p->rd_idle = rrddim_add(p->st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
134 rrddim_hide(p->st, "idle");
135
136 if (!is_total)
137 rrdlabels_add(p->st->rrdlabels, "cpu", windows_shared_buffer, RRDLABEL_SRC_AUTO);
138 else
139 cpus_var = rrdvar_host_variable_add_and_acquire(localhost, "active_processors");
140 }
141
142 uint64_t user = p->percentUserTime.current.Data;
143 uint64_t system = p->percentPrivilegedTime.current.Data;
144 uint64_t dpc = p->percentDPCTime.current.Data;
145 uint64_t irq = p->percentInterruptTime.current.Data;
146 uint64_t idle = p->percentIdleTime.current.Data;
147
148 totalIPC += p->interruptsPerSec.current.Data;
149
150 rrddim_set_by_pointer(p->st, p->rd_user, (collected_number)user);
151 rrddim_set_by_pointer(p->st, p->rd_system, (collected_number)system);
152 rrddim_set_by_pointer(p->st, p->rd_irq, (collected_number)irq);
153 rrddim_set_by_pointer(p->st, p->rd_dpc, (collected_number)dpc);
154 rrddim_set_by_pointer(p->st, p->rd_idle, (collected_number)idle);
155 rrdset_done(p->st);
156
157 // if(!p->st2) {
158 // p->st2 = rrdset_create_localhost(
159 // is_total ? "system" : "cpu2"
160 // , is_total ? "cpu3" : buffer
161 // , NULL
162 // , is_total ? "utilization" : buffer
163 // , is_total ? "system.cpu3" : "cpu2.cpu"
164 // , is_total ? "Total CPU Utilization" : "Core Utilization"
165 // , "percentage"
166 // , PLUGIN_WINDOWS_NAME
167 // , "PerflibProcessor"
168 // , is_total ? NETDATA_CHART_PRIO_SYSTEM_CPU : NETDATA_CHART_PRIO_CPU_PER_CORE
169 // , update_every
170 // , RRDSET_TYPE_STACKED
171 // );
172 //
173 // p->rd2_busy = perflib_rrddim_add(p->st2, "busy", NULL, 1, 1, &p->percentProcessorTime);
174 // rrddim_hide(p->st2, "idle");
175 //
176 // if(!is_total)
177 // rrdlabels_add(p->st->rrdlabels, "cpu", buffer, RRDLABEL_SRC_AUTO);
178 // }
179 //
180 // perflib_rrddim_set_by_pointer(p->st2, p->rd2_busy, &p->percentProcessorTime);
181 // rrdset_done(p->st2);
182 }
183
184 if (cpus_var)
185 rrdvar_host_variable_set(localhost, cpus_var, cores_found);
186
187 common_interrupts(totalIPC, update_every, NULL);
188
189 return true;
190 }
191
192 int do_PerflibProcessor(int update_every, usec_t dt __maybe_unused)
193 {
194 static bool initialized = false;
195
196 if (unlikely(!initialized)) {
197 initialize();
198 initialized = true;
199 }
200
201 DWORD id = RegistryFindIDByName("Processor");
202 if (id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
203 return -1;
204
205 PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
206 if (!pDataBlock)
207 return -1;
208
209 do_processors(pDataBlock, update_every);
210
211 return 0;
212 }