master
c 872 lines 29.9 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 "PerflibMemory"
8 #include "../common-contexts/common-contexts.h"
9
10 struct swap {
11 RRDSET *operations;
12 RRDDIM *rd_op_read;
13 RRDDIM *rd_op_write;
14
15 RRDSET *pages;
16 RRDDIM *rd_page_read;
17 RRDDIM *rd_page_write;
18
19 COUNTER_DATA pageReadsTotal;
20 COUNTER_DATA pageWritesTotal;
21 COUNTER_DATA pageInputTotal;
22 COUNTER_DATA pageOutputTotal;
23 };
24
25 struct commit {
26 RRDSET *chart;
27 RRDDIM *rd_committed;
28 RRDDIM *rd_limit;
29
30 COUNTER_DATA committedBytes;
31 COUNTER_DATA commitLimit;
32 };
33
34 struct system_cache {
35 RRDSET *chart;
36 RRDDIM *rd_cache;
37 RRDDIM *rd_peak;
38 RRDDIM *rd_resident;
39
40 COUNTER_DATA cacheBytes;
41 COUNTER_DATA cacheBytesPeak;
42 COUNTER_DATA residentBytes;
43 };
44
45 struct page_lists {
46 RRDSET *chart;
47 RRDDIM *rd_free;
48 RRDDIM *rd_modified;
49 RRDDIM *rd_standby_core;
50 RRDDIM *rd_standby_normal;
51 RRDDIM *rd_standby_reserve;
52
53 COUNTER_DATA freeAndZeroPageListBytes;
54 COUNTER_DATA modifiedPageListBytes;
55 COUNTER_DATA standbyCacheCoreBytes;
56 COUNTER_DATA standbyCacheNormalPriorityBytes;
57 COUNTER_DATA standbyCacheReserveBytes;
58 };
59
60 struct system_pool {
61 RRDSET *pool;
62 RRDDIM *rd_paged;
63 RRDDIM *rd_nonpaged;
64
65 RRDSET *paged;
66 RRDDIM *rd_paged_resident;
67
68 RRDSET *allocs;
69 RRDDIM *rd_allocs_paged;
70 RRDDIM *rd_allocs_nonpaged;
71
72 RRDSET *freeSystemPageTableEntries;
73 RRDDIM *rd_free_system_page_table_entries;
74
75 COUNTER_DATA pagedBytes;
76 COUNTER_DATA pagedResidentBytes;
77 COUNTER_DATA pagedAllocs;
78 COUNTER_DATA nonPagedBytes;
79 COUNTER_DATA nonPagedAllocs;
80 COUNTER_DATA pageTableEntries;
81 };
82
83 struct system_code {
84 RRDSET *chart;
85 RRDDIM *rd_resident;
86 RRDDIM *rd_total;
87
88 COUNTER_DATA residentBytes;
89 COUNTER_DATA totalBytes;
90 };
91
92 struct system_drivers {
93 RRDSET *chart;
94 RRDDIM *rd_resident;
95 RRDDIM *rd_total;
96
97 COUNTER_DATA residentBytes;
98 COUNTER_DATA totalBytes;
99 };
100
101 struct page_faults {
102 RRDSET *breakdown;
103 RRDDIM *rd_cache;
104 RRDDIM *rd_demand_zero;
105 RRDDIM *rd_transition;
106 RRDDIM *rd_write_copies;
107
108 RRDSET *transition_repurposed;
109 RRDDIM *rd_repurposed;
110
111 COUNTER_DATA cacheFaultsPerSec;
112 COUNTER_DATA demandZeroFaultsPerSec;
113 COUNTER_DATA transitionFaultsPerSec;
114 COUNTER_DATA transitionPagesRePurposedPerSec;
115 COUNTER_DATA writeCopiesPerSec;
116 };
117
118 static struct swap localSwap = {0};
119 static struct commit localCommit = {0};
120 static struct system_cache localCache = {0};
121 static struct page_lists localPageLists = {0};
122 static struct system_pool localPool = {0};
123 static struct system_code localCode = {0};
124 static struct system_drivers localDrivers = {0};
125 static struct page_faults localFaults = {0};
126
127 static void initialize_swap_keys(struct swap *p)
128 {
129 p->pageReadsTotal.key = "Page Reads/sec";
130 p->pageWritesTotal.key = "Page Writes/sec";
131 p->pageInputTotal.key = "Pages Input/sec";
132 p->pageOutputTotal.key = "Pages Output/sec";
133 }
134
135 static void initialize_commit_keys(struct commit *p)
136 {
137 p->committedBytes.key = "Committed Bytes";
138 p->commitLimit.key = "Commit Limit";
139 }
140
141 static void initialize_cache_keys(struct system_cache *p)
142 {
143 p->cacheBytes.key = "Cache Bytes";
144 p->cacheBytesPeak.key = "Cache Bytes Peak";
145 p->residentBytes.key = "System Cache Resident Bytes";
146 }
147
148 static void initialize_page_list_keys(struct page_lists *p)
149 {
150 p->freeAndZeroPageListBytes.key = "Free & Zero Page List Bytes";
151 p->modifiedPageListBytes.key = "Modified Page List Bytes";
152 p->standbyCacheCoreBytes.key = "Standby Cache Core Bytes";
153 p->standbyCacheNormalPriorityBytes.key = "Standby Cache Normal Priority Bytes";
154 p->standbyCacheReserveBytes.key = "Standby Cache Reserve Bytes";
155 }
156
157 static void initialize_pool_keys(struct system_pool *p)
158 {
159 p->pagedBytes.key = "Pool Paged Bytes";
160 p->pagedResidentBytes.key = "Pool Paged Resident Bytes";
161 p->pagedAllocs.key = "Pool Paged Allocs";
162 p->nonPagedBytes.key = "Pool Nonpaged Bytes";
163 p->nonPagedAllocs.key = "Pool Nonpaged Allocs";
164 p->pageTableEntries.key = "Free System Page Table Entries";
165 }
166
167 static void initialize_system_code_keys(struct system_code *p)
168 {
169 p->residentBytes.key = "System Code Resident Bytes";
170 p->totalBytes.key = "System Code Total Bytes";
171 }
172
173 static void initialize_system_driver_keys(struct system_drivers *p)
174 {
175 p->residentBytes.key = "System Driver Resident Bytes";
176 p->totalBytes.key = "System Driver Total Bytes";
177 }
178
179 static void initialize_fault_keys(struct page_faults *p)
180 {
181 p->cacheFaultsPerSec.key = "Cache Faults/sec";
182 p->demandZeroFaultsPerSec.key = "Demand Zero Faults/sec";
183 p->transitionFaultsPerSec.key = "Transition Faults/sec";
184 p->transitionPagesRePurposedPerSec.key = "Transition Pages RePurposed/sec";
185 p->writeCopiesPerSec.key = "Write Copies/sec";
186 }
187
188 static void initialize(void)
189 {
190 initialize_swap_keys(&localSwap);
191 initialize_commit_keys(&localCommit);
192 initialize_cache_keys(&localCache);
193 initialize_page_list_keys(&localPageLists);
194 initialize_pool_keys(&localPool);
195 initialize_system_code_keys(&localCode);
196 initialize_system_driver_keys(&localDrivers);
197 initialize_fault_keys(&localFaults);
198 }
199
200 static void do_memory_swap_operations_chart(
201 PERF_DATA_BLOCK *pDataBlock,
202 PERF_OBJECT_TYPE *pObjectType,
203 int update_every)
204 {
205 collected_number page_reads = 0;
206 collected_number page_writes = 0;
207 bool has_page_reads = perflibGetObjectCounter(pDataBlock, pObjectType, &localSwap.pageReadsTotal);
208 bool has_page_writes = perflibGetObjectCounter(pDataBlock, pObjectType, &localSwap.pageWritesTotal);
209
210 if (!has_page_reads && !has_page_writes)
211 return;
212
213 if (has_page_reads)
214 page_reads = (collected_number)localSwap.pageReadsTotal.current.Data;
215
216 if (has_page_writes)
217 page_writes = (collected_number)localSwap.pageWritesTotal.current.Data;
218
219 if (!localSwap.operations) {
220 localSwap.operations = rrdset_create_localhost(
221 "mem",
222 "swap_operations",
223 NULL,
224 "swap",
225 "mem.swap_iops",
226 "Swap Operations",
227 "operations/s",
228 PLUGIN_WINDOWS_NAME,
229 "PerflibMemory",
230 NETDATA_CHART_PRIO_MEM_SWAP_CALLS,
231 update_every,
232 RRDSET_TYPE_STACKED);
233
234 localSwap.rd_op_read = rrddim_add(localSwap.operations, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
235 localSwap.rd_op_write = rrddim_add(localSwap.operations, "write", NULL, 1, -1, RRD_ALGORITHM_INCREMENTAL);
236 }
237
238 rrddim_set_by_pointer(localSwap.operations, localSwap.rd_op_read, page_reads);
239 rrddim_set_by_pointer(localSwap.operations, localSwap.rd_op_write, page_writes);
240 rrdset_done(localSwap.operations);
241 }
242
243 static void do_memory_swap_pages_chart(
244 PERF_DATA_BLOCK *pDataBlock,
245 PERF_OBJECT_TYPE *pObjectType,
246 int update_every)
247 {
248 collected_number page_input = 0;
249 collected_number page_output = 0;
250 bool has_page_input = perflibGetObjectCounter(pDataBlock, pObjectType, &localSwap.pageInputTotal);
251 bool has_page_output = perflibGetObjectCounter(pDataBlock, pObjectType, &localSwap.pageOutputTotal);
252
253 if (!has_page_input && !has_page_output)
254 return;
255
256 if (has_page_input)
257 page_input = (collected_number)localSwap.pageInputTotal.current.Data;
258
259 if (has_page_output)
260 page_output = (collected_number)localSwap.pageOutputTotal.current.Data;
261
262 if (!localSwap.pages) {
263 localSwap.pages = rrdset_create_localhost(
264 "mem",
265 "swapio",
266 NULL,
267 "swap",
268 "mem.swapio",
269 "Swap I/O",
270 "KiB/s",
271 PLUGIN_WINDOWS_NAME,
272 "PerflibMemory",
273 NETDATA_CHART_PRIO_MEM_SWAPIO,
274 update_every,
275 RRDSET_TYPE_AREA);
276
277 // divide by 1024 to convert bytes to KiB/s
278 collected_number page_size = (collected_number)os_get_system_page_size();
279 localSwap.rd_page_read = rrddim_add(localSwap.pages, "in", NULL, page_size, 1024, RRD_ALGORITHM_INCREMENTAL);
280 localSwap.rd_page_write = rrddim_add(localSwap.pages, "out", NULL, -page_size, 1024, RRD_ALGORITHM_INCREMENTAL);
281 }
282
283 rrddim_set_by_pointer(localSwap.pages, localSwap.rd_page_read, page_input);
284 rrddim_set_by_pointer(localSwap.pages, localSwap.rd_page_write, page_output);
285 rrdset_done(localSwap.pages);
286 }
287
288 static void do_memory_swap(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, int update_every)
289 {
290 do_memory_swap_operations_chart(pDataBlock, pObjectType, update_every);
291 do_memory_swap_pages_chart(pDataBlock, pObjectType, update_every);
292 }
293
294 static void do_memory_commit(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, int update_every)
295 {
296 collected_number committed = 0;
297 collected_number limit = 0;
298 bool has_data = false;
299
300 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localCommit.committedBytes)) {
301 committed = (collected_number)localCommit.committedBytes.current.Data;
302 has_data = true;
303 }
304
305 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localCommit.commitLimit)) {
306 limit = (collected_number)localCommit.commitLimit.current.Data;
307 has_data = true;
308 }
309
310 if (!has_data)
311 return;
312
313 if (!localCommit.chart) {
314 localCommit.chart = rrdset_create_localhost(
315 "mem",
316 "committed",
317 NULL,
318 "mem",
319 "mem.committed",
320 "Committed Memory",
321 "bytes",
322 PLUGIN_WINDOWS_NAME,
323 "PerflibMemory",
324 NETDATA_CHART_PRIO_MEM_SYSTEM_COMMITTED,
325 update_every,
326 RRDSET_TYPE_LINE);
327
328 localCommit.rd_committed = rrddim_add(localCommit.chart, "committed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
329 localCommit.rd_limit = rrddim_add(localCommit.chart, "limit", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
330 }
331
332 rrddim_set_by_pointer(localCommit.chart, localCommit.rd_committed, committed);
333 rrddim_set_by_pointer(localCommit.chart, localCommit.rd_limit, limit);
334 rrdset_done(localCommit.chart);
335 }
336
337 static void do_memory_cache(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, int update_every)
338 {
339 collected_number cache = 0;
340 collected_number peak = 0;
341 collected_number resident = 0;
342 bool has_data = false;
343
344 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localCache.cacheBytes)) {
345 cache = (collected_number)localCache.cacheBytes.current.Data;
346 has_data = true;
347 }
348
349 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localCache.cacheBytesPeak)) {
350 peak = (collected_number)localCache.cacheBytesPeak.current.Data;
351 has_data = true;
352 }
353
354 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localCache.residentBytes)) {
355 resident = (collected_number)localCache.residentBytes.current.Data;
356 has_data = true;
357 }
358
359 if (!has_data)
360 return;
361
362 if (!localCache.chart) {
363 localCache.chart = rrdset_create_localhost(
364 "mem",
365 "system_cache",
366 NULL,
367 "mem",
368 "mem.system_cache",
369 "System Cache Memory",
370 "bytes",
371 PLUGIN_WINDOWS_NAME,
372 "PerflibMemory",
373 NETDATA_CHART_PRIO_MEM_SYSTEM_CACHE,
374 update_every,
375 RRDSET_TYPE_LINE);
376
377 localCache.rd_cache = rrddim_add(localCache.chart, "cache", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
378 localCache.rd_peak = rrddim_add(localCache.chart, "peak", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
379 localCache.rd_resident = rrddim_add(localCache.chart, "resident", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
380 }
381
382 rrddim_set_by_pointer(localCache.chart, localCache.rd_cache, cache);
383 rrddim_set_by_pointer(localCache.chart, localCache.rd_peak, peak);
384 rrddim_set_by_pointer(localCache.chart, localCache.rd_resident, resident);
385 rrdset_done(localCache.chart);
386 }
387
388 static void do_memory_page_lists(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, int update_every)
389 {
390 collected_number free_bytes = 0;
391 collected_number modified = 0;
392 collected_number standby_core = 0;
393 collected_number standby_normal = 0;
394 collected_number standby_reserve = 0;
395 bool has_data = false;
396
397 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localPageLists.freeAndZeroPageListBytes)) {
398 free_bytes = (collected_number)localPageLists.freeAndZeroPageListBytes.current.Data;
399 has_data = true;
400 }
401
402 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localPageLists.modifiedPageListBytes)) {
403 modified = (collected_number)localPageLists.modifiedPageListBytes.current.Data;
404 has_data = true;
405 }
406
407 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localPageLists.standbyCacheCoreBytes)) {
408 standby_core = (collected_number)localPageLists.standbyCacheCoreBytes.current.Data;
409 has_data = true;
410 }
411
412 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localPageLists.standbyCacheNormalPriorityBytes)) {
413 standby_normal = (collected_number)localPageLists.standbyCacheNormalPriorityBytes.current.Data;
414 has_data = true;
415 }
416
417 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localPageLists.standbyCacheReserveBytes)) {
418 standby_reserve = (collected_number)localPageLists.standbyCacheReserveBytes.current.Data;
419 has_data = true;
420 }
421
422 if (!has_data)
423 return;
424
425 if (!localPageLists.chart) {
426 localPageLists.chart = rrdset_create_localhost(
427 "mem",
428 "page_lists",
429 NULL,
430 "mem",
431 "mem.page_lists",
432 "Memory Page Lists",
433 "bytes",
434 PLUGIN_WINDOWS_NAME,
435 "PerflibMemory",
436 NETDATA_CHART_PRIO_MEM_SYSTEM_PAGE_LISTS,
437 update_every,
438 RRDSET_TYPE_STACKED);
439
440 localPageLists.rd_free = rrddim_add(localPageLists.chart, "free", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
441 localPageLists.rd_modified =
442 rrddim_add(localPageLists.chart, "modified", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
443 localPageLists.rd_standby_core =
444 rrddim_add(localPageLists.chart, "standby_core", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
445 localPageLists.rd_standby_normal =
446 rrddim_add(localPageLists.chart, "standby_normal", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
447 localPageLists.rd_standby_reserve =
448 rrddim_add(localPageLists.chart, "standby_reserve", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
449 }
450
451 rrddim_set_by_pointer(localPageLists.chart, localPageLists.rd_free, free_bytes);
452 rrddim_set_by_pointer(localPageLists.chart, localPageLists.rd_modified, modified);
453 rrddim_set_by_pointer(localPageLists.chart, localPageLists.rd_standby_core, standby_core);
454 rrddim_set_by_pointer(localPageLists.chart, localPageLists.rd_standby_normal, standby_normal);
455 rrddim_set_by_pointer(localPageLists.chart, localPageLists.rd_standby_reserve, standby_reserve);
456 rrdset_done(localPageLists.chart);
457 }
458
459 static void do_memory_system_pool_size_chart(
460 PERF_DATA_BLOCK *pDataBlock,
461 PERF_OBJECT_TYPE *pObjectType,
462 int update_every)
463 {
464 collected_number paged = 0;
465 collected_number nonpaged = 0;
466 bool has_paged = perflibGetObjectCounter(pDataBlock, pObjectType, &localPool.pagedBytes);
467 bool has_nonpaged = perflibGetObjectCounter(pDataBlock, pObjectType, &localPool.nonPagedBytes);
468
469 if (!has_paged && !has_nonpaged)
470 return;
471
472 if (has_paged)
473 paged = (collected_number)localPool.pagedBytes.current.Data;
474
475 if (has_nonpaged)
476 nonpaged = (collected_number)localPool.nonPagedBytes.current.Data;
477
478 if (!localPool.pool) {
479 localPool.pool = rrdset_create_localhost(
480 "mem",
481 "system_pool",
482 NULL,
483 "mem",
484 "mem.system_pool_size",
485 "System Memory Pool",
486 "bytes",
487 PLUGIN_WINDOWS_NAME,
488 "PerflibMemory",
489 NETDATA_CHART_PRIO_MEM_SYSTEM_POOL,
490 update_every,
491 RRDSET_TYPE_STACKED);
492
493 localPool.rd_paged = rrddim_add(localPool.pool, "paged", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
494 localPool.rd_nonpaged = rrddim_add(localPool.pool, "non-paged", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
495 }
496
497 rrddim_set_by_pointer(localPool.pool, localPool.rd_paged, paged);
498 rrddim_set_by_pointer(localPool.pool, localPool.rd_nonpaged, nonpaged);
499 rrdset_done(localPool.pool);
500 }
501
502 static void do_memory_system_pool_paged_chart(
503 PERF_DATA_BLOCK *pDataBlock,
504 PERF_OBJECT_TYPE *pObjectType,
505 int update_every)
506 {
507 if (!perflibGetObjectCounter(pDataBlock, pObjectType, &localPool.pagedResidentBytes))
508 return;
509
510 if (!localPool.paged) {
511 localPool.paged = rrdset_create_localhost(
512 "mem",
513 "system_pool_paged",
514 NULL,
515 "mem",
516 "mem.system_pool_paged",
517 "Paged System Memory Pool",
518 "bytes",
519 PLUGIN_WINDOWS_NAME,
520 "PerflibMemory",
521 NETDATA_CHART_PRIO_MEM_SYSTEM_POOL_PAGED,
522 update_every,
523 RRDSET_TYPE_LINE);
524
525 localPool.rd_paged_resident =
526 rrddim_add(localPool.paged, "resident", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
527 }
528
529 rrddim_set_by_pointer(
530 localPool.paged,
531 localPool.rd_paged_resident,
532 (collected_number)localPool.pagedResidentBytes.current.Data);
533 rrdset_done(localPool.paged);
534 }
535
536 static void do_memory_system_pool_allocs_chart(
537 PERF_DATA_BLOCK *pDataBlock,
538 PERF_OBJECT_TYPE *pObjectType,
539 int update_every)
540 {
541 collected_number paged_allocs = 0;
542 collected_number nonpaged_allocs = 0;
543 bool has_paged_allocs = perflibGetObjectCounter(pDataBlock, pObjectType, &localPool.pagedAllocs);
544 bool has_nonpaged_allocs = perflibGetObjectCounter(pDataBlock, pObjectType, &localPool.nonPagedAllocs);
545
546 if (!has_paged_allocs && !has_nonpaged_allocs)
547 return;
548
549 if (has_paged_allocs)
550 paged_allocs = (collected_number)localPool.pagedAllocs.current.Data;
551
552 if (has_nonpaged_allocs)
553 nonpaged_allocs = (collected_number)localPool.nonPagedAllocs.current.Data;
554
555 if (!localPool.allocs) {
556 localPool.allocs = rrdset_create_localhost(
557 "mem",
558 "system_pool_allocs",
559 NULL,
560 "mem",
561 "mem.system_pool_allocs",
562 "System Pool Allocations",
563 "allocations/s",
564 PLUGIN_WINDOWS_NAME,
565 "PerflibMemory",
566 NETDATA_CHART_PRIO_MEM_SYSTEM_POOL_ALLOCS,
567 update_every,
568 RRDSET_TYPE_LINE);
569
570 localPool.rd_allocs_paged = rrddim_add(localPool.allocs, "paged", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
571 localPool.rd_allocs_nonpaged =
572 rrddim_add(localPool.allocs, "non-paged", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
573 }
574
575 rrddim_set_by_pointer(localPool.allocs, localPool.rd_allocs_paged, paged_allocs);
576 rrddim_set_by_pointer(localPool.allocs, localPool.rd_allocs_nonpaged, nonpaged_allocs);
577 rrdset_done(localPool.allocs);
578 }
579
580 static void do_memory_system_pool(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, int update_every)
581 {
582 do_memory_system_pool_size_chart(pDataBlock, pObjectType, update_every);
583 do_memory_system_pool_paged_chart(pDataBlock, pObjectType, update_every);
584 do_memory_system_pool_allocs_chart(pDataBlock, pObjectType, update_every);
585 }
586
587 static void do_memory_page_table_entries(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, int update_every)
588 {
589 if (!perflibGetObjectCounter(pDataBlock, pObjectType, &localPool.pageTableEntries))
590 return;
591
592 if (!localPool.freeSystemPageTableEntries) {
593 localPool.freeSystemPageTableEntries = rrdset_create_localhost(
594 "mem",
595 "free_system_page_table_entries",
596 NULL,
597 "mem",
598 "mem.system_page_table_entries",
599 "Unused page table entries.",
600 "pages",
601 PLUGIN_WINDOWS_NAME,
602 "PerflibMemory",
603 NETDATA_CHART_PRIO_MEM_FREE_SYSTEM_PAGE,
604 update_every,
605 RRDSET_TYPE_LINE);
606
607 localPool.rd_free_system_page_table_entries =
608 rrddim_add(localPool.freeSystemPageTableEntries, "free", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
609 }
610
611 rrddim_set_by_pointer(
612 localPool.freeSystemPageTableEntries,
613 localPool.rd_free_system_page_table_entries,
614 (collected_number)localPool.pageTableEntries.current.Data);
615 rrdset_done(localPool.freeSystemPageTableEntries);
616 }
617
618 static void do_memory_system_code(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, int update_every)
619 {
620 collected_number resident = 0;
621 collected_number total = 0;
622 bool has_data = false;
623
624 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localCode.residentBytes)) {
625 resident = (collected_number)localCode.residentBytes.current.Data;
626 has_data = true;
627 }
628
629 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localCode.totalBytes)) {
630 total = (collected_number)localCode.totalBytes.current.Data;
631 has_data = true;
632 }
633
634 if (!has_data)
635 return;
636
637 if (!localCode.chart) {
638 localCode.chart = rrdset_create_localhost(
639 "mem",
640 "system_code",
641 NULL,
642 "mem",
643 "mem.system_code",
644 "System Code Memory",
645 "bytes",
646 PLUGIN_WINDOWS_NAME,
647 "PerflibMemory",
648 NETDATA_CHART_PRIO_MEM_SYSTEM_CODE,
649 update_every,
650 RRDSET_TYPE_LINE);
651
652 localCode.rd_resident = rrddim_add(localCode.chart, "resident", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
653 localCode.rd_total = rrddim_add(localCode.chart, "total", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
654 }
655
656 rrddim_set_by_pointer(localCode.chart, localCode.rd_resident, resident);
657 rrddim_set_by_pointer(localCode.chart, localCode.rd_total, total);
658 rrdset_done(localCode.chart);
659 }
660
661 static void do_memory_system_drivers(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, int update_every)
662 {
663 collected_number resident = 0;
664 collected_number total = 0;
665 bool has_data = false;
666
667 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localDrivers.residentBytes)) {
668 resident = (collected_number)localDrivers.residentBytes.current.Data;
669 has_data = true;
670 }
671
672 if (perflibGetObjectCounter(pDataBlock, pObjectType, &localDrivers.totalBytes)) {
673 total = (collected_number)localDrivers.totalBytes.current.Data;
674 has_data = true;
675 }
676
677 if (!has_data)
678 return;
679
680 if (!localDrivers.chart) {
681 localDrivers.chart = rrdset_create_localhost(
682 "mem",
683 "system_drivers",
684 NULL,
685 "mem",
686 "mem.system_drivers",
687 "System Driver Memory",
688 "bytes",
689 PLUGIN_WINDOWS_NAME,
690 "PerflibMemory",
691 NETDATA_CHART_PRIO_MEM_SYSTEM_DRIVERS,
692 update_every,
693 RRDSET_TYPE_LINE);
694
695 localDrivers.rd_resident =
696 rrddim_add(localDrivers.chart, "resident", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
697 localDrivers.rd_total = rrddim_add(localDrivers.chart, "total", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
698 }
699
700 rrddim_set_by_pointer(localDrivers.chart, localDrivers.rd_resident, resident);
701 rrddim_set_by_pointer(localDrivers.chart, localDrivers.rd_total, total);
702 rrdset_done(localDrivers.chart);
703 }
704
705 static void do_memory_faults_breakdown_chart(
706 PERF_DATA_BLOCK *pDataBlock,
707 PERF_OBJECT_TYPE *pObjectType,
708 int update_every)
709 {
710 collected_number cache = 0;
711 collected_number demand_zero = 0;
712 collected_number transition = 0;
713 collected_number write_copies = 0;
714 bool has_cache = perflibGetObjectCounter(pDataBlock, pObjectType, &localFaults.cacheFaultsPerSec);
715 bool has_demand_zero = perflibGetObjectCounter(pDataBlock, pObjectType, &localFaults.demandZeroFaultsPerSec);
716 bool has_transition = perflibGetObjectCounter(pDataBlock, pObjectType, &localFaults.transitionFaultsPerSec);
717 bool has_write_copies = perflibGetObjectCounter(pDataBlock, pObjectType, &localFaults.writeCopiesPerSec);
718
719 if (!has_cache && !has_demand_zero && !has_transition && !has_write_copies)
720 return;
721
722 if (has_cache)
723 cache = (collected_number)localFaults.cacheFaultsPerSec.current.Data;
724
725 if (has_demand_zero)
726 demand_zero = (collected_number)localFaults.demandZeroFaultsPerSec.current.Data;
727
728 if (has_transition)
729 transition = (collected_number)localFaults.transitionFaultsPerSec.current.Data;
730
731 if (has_write_copies)
732 write_copies = (collected_number)localFaults.writeCopiesPerSec.current.Data;
733
734 if (!localFaults.breakdown) {
735 localFaults.breakdown = rrdset_create_localhost(
736 "mem",
737 "page_faults_breakdown",
738 NULL,
739 "page faults",
740 "mem.page_faults_breakdown",
741 "Memory Page Fault Breakdown",
742 "faults/s",
743 PLUGIN_WINDOWS_NAME,
744 "PerflibMemory",
745 NETDATA_CHART_PRIO_MEM_SYSTEM_PGFAULTS_DETAIL,
746 update_every,
747 RRDSET_TYPE_LINE);
748
749 localFaults.rd_cache =
750 rrddim_add(localFaults.breakdown, "cache", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
751 localFaults.rd_demand_zero =
752 rrddim_add(localFaults.breakdown, "demand_zero", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
753 localFaults.rd_transition =
754 rrddim_add(localFaults.breakdown, "transition", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
755 localFaults.rd_write_copies =
756 rrddim_add(localFaults.breakdown, "write_copies", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
757 }
758
759 rrddim_set_by_pointer(localFaults.breakdown, localFaults.rd_cache, cache);
760 rrddim_set_by_pointer(localFaults.breakdown, localFaults.rd_demand_zero, demand_zero);
761 rrddim_set_by_pointer(localFaults.breakdown, localFaults.rd_transition, transition);
762 rrddim_set_by_pointer(localFaults.breakdown, localFaults.rd_write_copies, write_copies);
763 rrdset_done(localFaults.breakdown);
764 }
765
766 static void do_memory_transition_repurposed_chart(
767 PERF_DATA_BLOCK *pDataBlock,
768 PERF_OBJECT_TYPE *pObjectType,
769 int update_every)
770 {
771 collected_number repurposed = 0;
772
773 if (!perflibGetObjectCounter(pDataBlock, pObjectType, &localFaults.transitionPagesRePurposedPerSec))
774 return;
775
776 repurposed = (collected_number)localFaults.transitionPagesRePurposedPerSec.current.Data;
777
778 if (!localFaults.transition_repurposed) {
779 localFaults.transition_repurposed = rrdset_create_localhost(
780 "mem",
781 "transition_repurposed",
782 NULL,
783 "page faults",
784 "mem.transition_repurposed",
785 "Transition Pages Repurposed",
786 "pages/s",
787 PLUGIN_WINDOWS_NAME,
788 "PerflibMemory",
789 NETDATA_CHART_PRIO_MEM_SYSTEM_TRANSITION,
790 update_every,
791 RRDSET_TYPE_LINE);
792
793 localFaults.rd_repurposed = rrddim_add(
794 localFaults.transition_repurposed, "repurposed", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
795 }
796
797 rrddim_set_by_pointer(localFaults.transition_repurposed, localFaults.rd_repurposed, repurposed);
798 rrdset_done(localFaults.transition_repurposed);
799 }
800
801 static void do_memory_faults(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, int update_every)
802 {
803 do_memory_faults_breakdown_chart(pDataBlock, pObjectType, update_every);
804 do_memory_transition_repurposed_chart(pDataBlock, pObjectType, update_every);
805 }
806
807 static bool do_memory(PERF_DATA_BLOCK *pDataBlock, int update_every)
808 {
809 PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "Memory");
810 if (!pObjectType)
811 return false;
812
813 static COUNTER_DATA pagesPerSec = {.key = "Pages/sec"};
814 static COUNTER_DATA pageFaultsPerSec = {.key = "Page Faults/sec"};
815
816 if (perflibGetObjectCounter(pDataBlock, pObjectType, &pageFaultsPerSec) &&
817 perflibGetObjectCounter(pDataBlock, pObjectType, &pagesPerSec)) {
818 ULONGLONG total = pageFaultsPerSec.current.Data;
819 ULONGLONG major = pagesPerSec.current.Data;
820 ULONGLONG minor = (total > major) ? total - major : 0;
821 common_mem_pgfaults(minor, major, update_every);
822 }
823
824 static COUNTER_DATA availableBytes = {.key = "Available Bytes"};
825 static COUNTER_DATA availableKBytes = {.key = "Available KBytes"};
826 static COUNTER_DATA availableMBytes = {.key = "Available MBytes"};
827 ULONGLONG available_bytes = 0;
828
829 if (perflibGetObjectCounter(pDataBlock, pObjectType, &availableBytes))
830 available_bytes = availableBytes.current.Data;
831 else if (perflibGetObjectCounter(pDataBlock, pObjectType, &availableKBytes))
832 available_bytes = availableKBytes.current.Data * 1024;
833 else if (perflibGetObjectCounter(pDataBlock, pObjectType, &availableMBytes))
834 available_bytes = availableMBytes.current.Data * 1024 * 1024;
835
836 common_mem_available(available_bytes, update_every);
837
838 do_memory_swap(pDataBlock, pObjectType, update_every);
839 do_memory_commit(pDataBlock, pObjectType, update_every);
840 do_memory_cache(pDataBlock, pObjectType, update_every);
841 do_memory_page_lists(pDataBlock, pObjectType, update_every);
842 do_memory_system_pool(pDataBlock, pObjectType, update_every);
843 do_memory_page_table_entries(pDataBlock, pObjectType, update_every);
844 do_memory_system_code(pDataBlock, pObjectType, update_every);
845 do_memory_system_drivers(pDataBlock, pObjectType, update_every);
846 do_memory_faults(pDataBlock, pObjectType, update_every);
847
848 return true;
849 }
850
851 int do_PerflibMemory(int update_every, usec_t dt __maybe_unused)
852 {
853 static bool initialized = false;
854
855 if (unlikely(!initialized)) {
856 initialize();
857 initialized = true;
858 }
859
860 DWORD id = RegistryFindIDByName("Memory");
861 if (id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
862 return -1;
863
864 PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
865 if (!pDataBlock)
866 return -1;
867
868 if (!do_memory(pDataBlock, update_every))
869 return -1;
870
871 return 0;
872 }