| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "plugin_proc.h" |
| 4 | |
| 5 | #define PLUGIN_PROC_MODULE_MEMINFO_NAME "/proc/meminfo" |
| 6 | #define CONFIG_SECTION_PLUGIN_PROC_MEMINFO "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 7 | |
| 8 | #define _COMMON_PLUGIN_NAME PLUGIN_PROC_NAME |
| 9 | #define _COMMON_PLUGIN_MODULE_NAME PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 10 | #include "../common-contexts/common-contexts.h" |
| 11 | |
| 12 | int do_proc_meminfo(int update_every, usec_t dt) { |
| 13 | (void)dt; |
| 14 | |
| 15 | static bool swap_configured = false; |
| 16 | |
| 17 | static procfile *ff = NULL; |
| 18 | static int do_ram = -1 |
| 19 | , do_swap = -1 |
| 20 | , do_hwcorrupt = -1 |
| 21 | , do_committed = -1 |
| 22 | , do_writeback = -1 |
| 23 | , do_kernel = -1 |
| 24 | , do_slab = -1 |
| 25 | , do_hugepages = -1 |
| 26 | , do_transparent_hugepages = -1 |
| 27 | , do_reclaiming = -1 |
| 28 | , do_high_low = -1 |
| 29 | , do_cma = -1 |
| 30 | , do_directmap = -1; |
| 31 | |
| 32 | static ARL_BASE *arl_base = NULL; |
| 33 | static ARL_ENTRY *arl_hwcorrupted = NULL, *arl_memavailable = NULL, *arl_hugepages_total = NULL, |
| 34 | *arl_zswapped = NULL, *arl_high_low = NULL, |
| 35 | *arl_directmap4k = NULL, *arl_directmap2m = NULL, *arl_directmap4m = NULL, *arl_directmap1g = NULL; |
| 36 | |
| 37 | static unsigned long long |
| 38 | MemTotal = 0 |
| 39 | , MemFree = 0 |
| 40 | , MemAvailable = 0 |
| 41 | , Buffers = 0 |
| 42 | , Cached = 0 |
| 43 | , SwapCached = 0 |
| 44 | , Active = 0 |
| 45 | , Inactive = 0 |
| 46 | , ActiveAnon = 0 |
| 47 | , InactiveAnon = 0 |
| 48 | , ActiveFile = 0 |
| 49 | , InactiveFile = 0 |
| 50 | , Unevictable = 0 |
| 51 | , Mlocked = 0 |
| 52 | , HighTotal = 0 |
| 53 | , HighFree = 0 |
| 54 | , LowTotal = 0 |
| 55 | , LowFree = 0 |
| 56 | , MmapCopy = 0 |
| 57 | , SwapTotal = 0 |
| 58 | , SwapFree = 0 |
| 59 | , Zswap = 0 |
| 60 | , Zswapped = 0 |
| 61 | , Dirty = 0 |
| 62 | , Writeback = 0 |
| 63 | , AnonPages = 0 |
| 64 | , Mapped = 0 |
| 65 | , Shmem = 0 |
| 66 | , KReclaimable = 0 |
| 67 | , Slab = 0 |
| 68 | , SReclaimable = 0 |
| 69 | , SUnreclaim = 0 |
| 70 | , KernelStack = 0 |
| 71 | , ShadowCallStack = 0 |
| 72 | , PageTables = 0 |
| 73 | , SecPageTables = 0 |
| 74 | , NFS_Unstable = 0 |
| 75 | , Bounce = 0 |
| 76 | , WritebackTmp = 0 |
| 77 | , CommitLimit = 0 |
| 78 | , Committed_AS = 0 |
| 79 | , VmallocTotal = 0 |
| 80 | , VmallocUsed = 0 |
| 81 | , VmallocChunk = 0 |
| 82 | , Percpu = 0 |
| 83 | //, EarlyMemtestBad = 0 |
| 84 | , HardwareCorrupted = 0 |
| 85 | , AnonHugePages = 0 |
| 86 | , ShmemHugePages = 0 |
| 87 | , ShmemPmdMapped = 0 |
| 88 | , FileHugePages = 0 |
| 89 | , FilePmdMapped = 0 |
| 90 | , CmaTotal = 0 |
| 91 | , CmaFree = 0 |
| 92 | //, Unaccepted = 0 |
| 93 | , HugePages_Total = 0 |
| 94 | , HugePages_Free = 0 |
| 95 | , HugePages_Rsvd = 0 |
| 96 | , HugePages_Surp = 0 |
| 97 | , Hugepagesize = 0 |
| 98 | //, Hugetlb = 0 |
| 99 | , DirectMap4k = 0 |
| 100 | , DirectMap2M = 0 |
| 101 | , DirectMap4M = 0 |
| 102 | , DirectMap1G = 0 |
| 103 | ; |
| 104 | |
| 105 | if(unlikely(!arl_base)) { |
| 106 | do_ram = inicfg_get_boolean(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "system ram", CONFIG_BOOLEAN_YES); |
| 107 | do_swap = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "system swap", CONFIG_BOOLEAN_AUTO); |
| 108 | do_hwcorrupt = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "hardware corrupted ECC", CONFIG_BOOLEAN_AUTO); |
| 109 | do_committed = inicfg_get_boolean(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "committed memory", CONFIG_BOOLEAN_YES); |
| 110 | do_writeback = inicfg_get_boolean(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "writeback memory", CONFIG_BOOLEAN_YES); |
| 111 | do_kernel = inicfg_get_boolean(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "kernel memory", CONFIG_BOOLEAN_YES); |
| 112 | do_slab = inicfg_get_boolean(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "slab memory", CONFIG_BOOLEAN_YES); |
| 113 | do_hugepages = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "hugepages", CONFIG_BOOLEAN_AUTO); |
| 114 | do_transparent_hugepages = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "transparent hugepages", CONFIG_BOOLEAN_AUTO); |
| 115 | do_reclaiming = inicfg_get_boolean(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "memory reclaiming", CONFIG_BOOLEAN_AUTO); |
| 116 | do_high_low = inicfg_get_boolean(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "high low memory", CONFIG_BOOLEAN_AUTO); |
| 117 | do_cma = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "cma memory", CONFIG_BOOLEAN_AUTO); |
| 118 | do_directmap = inicfg_get_boolean(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "direct maps", CONFIG_BOOLEAN_AUTO); |
| 119 | |
| 120 | // https://github.com/torvalds/linux/blob/master/fs/proc/meminfo.c |
| 121 | |
| 122 | arl_base = arl_create("meminfo", NULL, 60); |
| 123 | arl_expect(arl_base, "MemTotal", &MemTotal); |
| 124 | arl_expect(arl_base, "MemFree", &MemFree); |
| 125 | arl_memavailable = arl_expect(arl_base, "MemAvailable", &MemAvailable); |
| 126 | arl_expect(arl_base, "Buffers", &Buffers); |
| 127 | arl_expect(arl_base, "Cached", &Cached); |
| 128 | arl_expect(arl_base, "SwapCached", &SwapCached); |
| 129 | arl_expect(arl_base, "Active", &Active); |
| 130 | arl_expect(arl_base, "Inactive", &Inactive); |
| 131 | arl_expect(arl_base, "Active(anon)", &ActiveAnon); |
| 132 | arl_expect(arl_base, "Inactive(anon)", &InactiveAnon); |
| 133 | arl_expect(arl_base, "Active(file)", &ActiveFile); |
| 134 | arl_expect(arl_base, "Inactive(file)", &InactiveFile); |
| 135 | arl_expect(arl_base, "Unevictable", &Unevictable); |
| 136 | arl_expect(arl_base, "Mlocked", &Mlocked); |
| 137 | |
| 138 | // CONFIG_HIGHMEM |
| 139 | arl_high_low = arl_expect(arl_base, "HighTotal", &HighTotal); |
| 140 | arl_expect(arl_base, "HighFree", &HighFree); |
| 141 | arl_expect(arl_base, "LowTotal", &LowTotal); |
| 142 | arl_expect(arl_base, "LowFree", &LowFree); |
| 143 | |
| 144 | // CONFIG_MMU |
| 145 | arl_expect(arl_base, "MmapCopy", &MmapCopy); |
| 146 | |
| 147 | arl_expect(arl_base, "SwapTotal", &SwapTotal); |
| 148 | arl_expect(arl_base, "SwapFree", &SwapFree); |
| 149 | |
| 150 | // CONFIG_ZSWAP |
| 151 | arl_zswapped = arl_expect(arl_base, "Zswap", &Zswap); |
| 152 | arl_expect(arl_base, "Zswapped", &Zswapped); |
| 153 | |
| 154 | arl_expect(arl_base, "Dirty", &Dirty); |
| 155 | arl_expect(arl_base, "Writeback", &Writeback); |
| 156 | arl_expect(arl_base, "AnonPages", &AnonPages); |
| 157 | arl_expect(arl_base, "Mapped", &Mapped); |
| 158 | arl_expect(arl_base, "Shmem", &Shmem); |
| 159 | arl_expect(arl_base, "KReclaimable", &KReclaimable); |
| 160 | arl_expect(arl_base, "Slab", &Slab); |
| 161 | arl_expect(arl_base, "SReclaimable", &SReclaimable); |
| 162 | arl_expect(arl_base, "SUnreclaim", &SUnreclaim); |
| 163 | arl_expect(arl_base, "KernelStack", &KernelStack); |
| 164 | |
| 165 | // CONFIG_SHADOW_CALL_STACK |
| 166 | arl_expect(arl_base, "ShadowCallStack", &ShadowCallStack); |
| 167 | |
| 168 | arl_expect(arl_base, "PageTables", &PageTables); |
| 169 | arl_expect(arl_base, "SecPageTables", &SecPageTables); |
| 170 | arl_expect(arl_base, "NFS_Unstable", &NFS_Unstable); |
| 171 | arl_expect(arl_base, "Bounce", &Bounce); |
| 172 | arl_expect(arl_base, "WritebackTmp", &WritebackTmp); |
| 173 | arl_expect(arl_base, "CommitLimit", &CommitLimit); |
| 174 | arl_expect(arl_base, "Committed_AS", &Committed_AS); |
| 175 | arl_expect(arl_base, "VmallocTotal", &VmallocTotal); |
| 176 | arl_expect(arl_base, "VmallocUsed", &VmallocUsed); |
| 177 | arl_expect(arl_base, "VmallocChunk", &VmallocChunk); |
| 178 | arl_expect(arl_base, "Percpu", &Percpu); |
| 179 | |
| 180 | // CONFIG_MEMTEST |
| 181 | //arl_expect(arl_base, "EarlyMemtestBad", &EarlyMemtestBad); |
| 182 | |
| 183 | // CONFIG_MEMORY_FAILURE |
| 184 | arl_hwcorrupted = arl_expect(arl_base, "HardwareCorrupted", &HardwareCorrupted); |
| 185 | |
| 186 | // CONFIG_TRANSPARENT_HUGEPAGE |
| 187 | arl_expect(arl_base, "AnonHugePages", &AnonHugePages); |
| 188 | arl_expect(arl_base, "ShmemHugePages", &ShmemHugePages); |
| 189 | arl_expect(arl_base, "ShmemPmdMapped", &ShmemPmdMapped); |
| 190 | arl_expect(arl_base, "FileHugePages", &FileHugePages); |
| 191 | arl_expect(arl_base, "FilePmdMapped", &FilePmdMapped); |
| 192 | |
| 193 | // CONFIG_CMA |
| 194 | arl_expect(arl_base, "CmaTotal", &CmaTotal); |
| 195 | arl_expect(arl_base, "CmaFree", &CmaFree); |
| 196 | |
| 197 | // CONFIG_UNACCEPTED_MEMORY |
| 198 | //arl_expect(arl_base, "Unaccepted", &Unaccepted); |
| 199 | |
| 200 | // these appear only when hugepages are supported |
| 201 | arl_hugepages_total = arl_expect(arl_base, "HugePages_Total", &HugePages_Total); |
| 202 | arl_expect(arl_base, "HugePages_Free", &HugePages_Free); |
| 203 | arl_expect(arl_base, "HugePages_Rsvd", &HugePages_Rsvd); |
| 204 | arl_expect(arl_base, "HugePages_Surp", &HugePages_Surp); |
| 205 | arl_expect(arl_base, "Hugepagesize", &Hugepagesize); |
| 206 | //arl_expect(arl_base, "Hugetlb", &Hugetlb); |
| 207 | |
| 208 | arl_directmap4k = arl_expect(arl_base, "DirectMap4k", &DirectMap4k); |
| 209 | arl_directmap2m = arl_expect(arl_base, "DirectMap2M", &DirectMap2M); |
| 210 | arl_directmap4m = arl_expect(arl_base, "DirectMap4M", &DirectMap4M); |
| 211 | arl_directmap1g = arl_expect(arl_base, "DirectMap1G", &DirectMap1G); |
| 212 | } |
| 213 | |
| 214 | if(unlikely(!ff)) { |
| 215 | char filename[FILENAME_MAX + 1]; |
| 216 | snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/meminfo"); |
| 217 | ff = procfile_open(inicfg_get(&netdata_config, CONFIG_SECTION_PLUGIN_PROC_MEMINFO, "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT); |
| 218 | if(unlikely(!ff)) |
| 219 | return 1; |
| 220 | } |
| 221 | |
| 222 | ff = procfile_readall(ff); |
| 223 | if(unlikely(!ff)) |
| 224 | return 0; // we return 0, so that we will retry to open it next time |
| 225 | |
| 226 | size_t lines = procfile_lines(ff), l; |
| 227 | |
| 228 | arl_begin(arl_base); |
| 229 | for(l = 0; l < lines ;l++) { |
| 230 | size_t words = procfile_linewords(ff, l); |
| 231 | if(unlikely(words < 2)) continue; |
| 232 | |
| 233 | if(unlikely(arl_check(arl_base, |
| 234 | procfile_lineword(ff, l, 0), |
| 235 | procfile_lineword(ff, l, 1)))) break; |
| 236 | } |
| 237 | |
| 238 | // http://calimeroteknik.free.fr/blag/?article20/really-used-memory-on-gnu-linux |
| 239 | // KReclaimable includes SReclaimable, it was added in kernel v4.20 |
| 240 | unsigned long long reclaimable = inside_lxc_container ? 0 : (KReclaimable > 0 ? KReclaimable : SReclaimable); |
| 241 | unsigned long long MemCached = Cached + reclaimable - Shmem; |
| 242 | unsigned long long MemUsed = MemTotal - MemFree - MemCached - Buffers; |
| 243 | // The Linux kernel doesn't report ZFS ARC usage as cache memory (the ARC is included in the total used system memory) |
| 244 | if (!inside_lxc_container) { |
| 245 | MemCached += (zfs_arcstats_shrinkable_cache_size_bytes / 1024); |
| 246 | MemUsed -= (zfs_arcstats_shrinkable_cache_size_bytes / 1024); |
| 247 | MemAvailable += (zfs_arcstats_shrinkable_cache_size_bytes / 1024); |
| 248 | } |
| 249 | |
| 250 | if(do_ram) { |
| 251 | common_system_ram(MemFree * 1024, MemUsed * 1024, MemCached * 1024, Buffers * 1024, update_every); |
| 252 | |
| 253 | if(arl_memavailable->flags & ARL_ENTRY_FLAG_FOUND) |
| 254 | common_mem_available(MemAvailable * 1024, update_every); |
| 255 | } |
| 256 | |
| 257 | unsigned long long SwapUsed = SwapTotal - SwapFree; |
| 258 | |
| 259 | if (SwapTotal && (do_swap == CONFIG_BOOLEAN_YES || do_swap == CONFIG_BOOLEAN_AUTO)) { |
| 260 | do_swap = CONFIG_BOOLEAN_YES; |
| 261 | common_mem_swap(SwapFree * 1024, SwapUsed * 1024, update_every); |
| 262 | swap_configured = true; |
| 263 | |
| 264 | { |
| 265 | static RRDSET *st_mem_swap_cached = NULL; |
| 266 | static RRDDIM *rd_cached = NULL; |
| 267 | |
| 268 | if (unlikely(!st_mem_swap_cached)) { |
| 269 | st_mem_swap_cached = rrdset_create_localhost( |
| 270 | "mem" |
| 271 | , "swap_cached" |
| 272 | , NULL |
| 273 | , "swap" |
| 274 | , NULL |
| 275 | , "Swap Memory Cached in RAM" |
| 276 | , "MiB" |
| 277 | , PLUGIN_PROC_NAME |
| 278 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 279 | , NETDATA_CHART_PRIO_MEM_SWAP + 1 |
| 280 | , update_every |
| 281 | , RRDSET_TYPE_AREA |
| 282 | ); |
| 283 | |
| 284 | rd_cached = rrddim_add(st_mem_swap_cached, "cached", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 285 | } |
| 286 | |
| 287 | rrddim_set_by_pointer(st_mem_swap_cached, rd_cached, SwapCached); |
| 288 | rrdset_done(st_mem_swap_cached); |
| 289 | } |
| 290 | |
| 291 | if (is_mem_zswap_enabled && (arl_zswapped->flags & ARL_ENTRY_FLAG_FOUND)) { |
| 292 | static RRDSET *st_mem_zswap = NULL; |
| 293 | static RRDDIM *rd_zswap = NULL, *rd_zswapped = NULL; |
| 294 | |
| 295 | if (unlikely(!st_mem_zswap)) { |
| 296 | st_mem_zswap = rrdset_create_localhost( |
| 297 | "mem" |
| 298 | , "zswap" |
| 299 | , NULL |
| 300 | , "zswap" |
| 301 | , NULL |
| 302 | , "Zswap Usage" |
| 303 | , "MiB" |
| 304 | , PLUGIN_PROC_NAME |
| 305 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 306 | , NETDATA_CHART_PRIO_MEM_ZSWAP |
| 307 | , update_every |
| 308 | , RRDSET_TYPE_STACKED |
| 309 | ); |
| 310 | |
| 311 | rd_zswap = rrddim_add(st_mem_zswap, "zswap", "in-ram", 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 312 | rd_zswapped = rrddim_add(st_mem_zswap, "zswapped", "on-disk", 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 313 | } |
| 314 | |
| 315 | rrddim_set_by_pointer(st_mem_zswap, rd_zswap, Zswap); |
| 316 | rrddim_set_by_pointer(st_mem_zswap, rd_zswapped, Zswapped); |
| 317 | rrdset_done(st_mem_zswap); |
| 318 | } |
| 319 | } else { |
| 320 | if (swap_configured) { |
| 321 | common_mem_swap(SwapFree * 1024, SwapUsed * 1024, update_every); |
| 322 | swap_configured = false; |
| 323 | } |
| 324 | } |
| 325 | |
| 326 | |
| 327 | if (arl_hwcorrupted->flags & ARL_ENTRY_FLAG_FOUND && |
| 328 | (do_hwcorrupt == CONFIG_BOOLEAN_YES || do_hwcorrupt == CONFIG_BOOLEAN_AUTO)) { |
| 329 | do_hwcorrupt = CONFIG_BOOLEAN_YES; |
| 330 | |
| 331 | static RRDSET *st_mem_hwcorrupt = NULL; |
| 332 | static RRDDIM *rd_corrupted = NULL; |
| 333 | |
| 334 | if(unlikely(!st_mem_hwcorrupt)) { |
| 335 | st_mem_hwcorrupt = rrdset_create_localhost( |
| 336 | "mem" |
| 337 | , "hwcorrupt" |
| 338 | , NULL |
| 339 | , "ecc" |
| 340 | , NULL |
| 341 | , "Corrupted Memory, detected by ECC" |
| 342 | , "MiB" |
| 343 | , PLUGIN_PROC_NAME |
| 344 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 345 | , NETDATA_CHART_PRIO_MEM_HW |
| 346 | , update_every |
| 347 | , RRDSET_TYPE_LINE |
| 348 | ); |
| 349 | |
| 350 | rd_corrupted = rrddim_add(st_mem_hwcorrupt, "HardwareCorrupted", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 351 | } |
| 352 | |
| 353 | rrddim_set_by_pointer(st_mem_hwcorrupt, rd_corrupted, HardwareCorrupted); |
| 354 | rrdset_done(st_mem_hwcorrupt); |
| 355 | } |
| 356 | |
| 357 | if(do_committed) { |
| 358 | static RRDSET *st_mem_committed = NULL; |
| 359 | static RRDDIM *rd_committed = NULL; |
| 360 | |
| 361 | if(unlikely(!st_mem_committed)) { |
| 362 | st_mem_committed = rrdset_create_localhost( |
| 363 | "mem" |
| 364 | , "committed" |
| 365 | , NULL |
| 366 | , "overview" |
| 367 | , NULL |
| 368 | , "Committed (Allocated) Memory" |
| 369 | , "MiB" |
| 370 | , PLUGIN_PROC_NAME |
| 371 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 372 | , NETDATA_CHART_PRIO_MEM_SYSTEM_COMMITTED |
| 373 | , update_every |
| 374 | , RRDSET_TYPE_AREA |
| 375 | ); |
| 376 | |
| 377 | rd_committed = rrddim_add(st_mem_committed, "Committed_AS", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 378 | } |
| 379 | |
| 380 | rrddim_set_by_pointer(st_mem_committed, rd_committed, Committed_AS); |
| 381 | rrdset_done(st_mem_committed); |
| 382 | } |
| 383 | |
| 384 | if(do_writeback) { |
| 385 | static RRDSET *st_mem_writeback = NULL; |
| 386 | static RRDDIM *rd_dirty = NULL, *rd_writeback = NULL, *rd_fusewriteback = NULL, *rd_nfs_writeback = NULL, *rd_bounce = NULL; |
| 387 | |
| 388 | if(unlikely(!st_mem_writeback)) { |
| 389 | st_mem_writeback = rrdset_create_localhost( |
| 390 | "mem" |
| 391 | , "writeback" |
| 392 | , NULL |
| 393 | , "writeback" |
| 394 | , NULL |
| 395 | , "Writeback Memory" |
| 396 | , "MiB" |
| 397 | , PLUGIN_PROC_NAME |
| 398 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 399 | , NETDATA_CHART_PRIO_MEM_KERNEL |
| 400 | , update_every |
| 401 | , RRDSET_TYPE_LINE |
| 402 | ); |
| 403 | |
| 404 | rd_dirty = rrddim_add(st_mem_writeback, "Dirty", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 405 | rd_writeback = rrddim_add(st_mem_writeback, "Writeback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 406 | rd_fusewriteback = rrddim_add(st_mem_writeback, "FuseWriteback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 407 | rd_nfs_writeback = rrddim_add(st_mem_writeback, "NfsWriteback", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 408 | rd_bounce = rrddim_add(st_mem_writeback, "Bounce", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 409 | } |
| 410 | |
| 411 | rrddim_set_by_pointer(st_mem_writeback, rd_dirty, Dirty); |
| 412 | rrddim_set_by_pointer(st_mem_writeback, rd_writeback, Writeback); |
| 413 | rrddim_set_by_pointer(st_mem_writeback, rd_fusewriteback, WritebackTmp); |
| 414 | rrddim_set_by_pointer(st_mem_writeback, rd_nfs_writeback, NFS_Unstable); |
| 415 | rrddim_set_by_pointer(st_mem_writeback, rd_bounce, Bounce); |
| 416 | rrdset_done(st_mem_writeback); |
| 417 | } |
| 418 | |
| 419 | // -------------------------------------------------------------------- |
| 420 | |
| 421 | if(do_kernel) { |
| 422 | static RRDSET *st_mem_kernel = NULL; |
| 423 | static RRDDIM *rd_slab = NULL, *rd_kernelstack = NULL, *rd_pagetables = NULL, *rd_vmallocused = NULL, |
| 424 | *rd_percpu = NULL, *rd_kreclaimable = NULL; |
| 425 | |
| 426 | if(unlikely(!st_mem_kernel)) { |
| 427 | st_mem_kernel = rrdset_create_localhost( |
| 428 | "mem" |
| 429 | , "kernel" |
| 430 | , NULL |
| 431 | , "kernel" |
| 432 | , NULL |
| 433 | , "Memory Used by Kernel" |
| 434 | , "MiB" |
| 435 | , PLUGIN_PROC_NAME |
| 436 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 437 | , NETDATA_CHART_PRIO_MEM_KERNEL + 1 |
| 438 | , update_every |
| 439 | , RRDSET_TYPE_STACKED |
| 440 | ); |
| 441 | |
| 442 | rd_slab = rrddim_add(st_mem_kernel, "Slab", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 443 | rd_kernelstack = rrddim_add(st_mem_kernel, "KernelStack", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 444 | rd_pagetables = rrddim_add(st_mem_kernel, "PageTables", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 445 | rd_vmallocused = rrddim_add(st_mem_kernel, "VmallocUsed", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 446 | rd_percpu = rrddim_add(st_mem_kernel, "Percpu", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 447 | rd_kreclaimable = rrddim_add(st_mem_kernel, "KReclaimable", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 448 | } |
| 449 | |
| 450 | rrddim_set_by_pointer(st_mem_kernel, rd_slab, Slab); |
| 451 | rrddim_set_by_pointer(st_mem_kernel, rd_kernelstack, KernelStack); |
| 452 | rrddim_set_by_pointer(st_mem_kernel, rd_pagetables, PageTables); |
| 453 | rrddim_set_by_pointer(st_mem_kernel, rd_vmallocused, VmallocUsed); |
| 454 | rrddim_set_by_pointer(st_mem_kernel, rd_percpu, Percpu); |
| 455 | rrddim_set_by_pointer(st_mem_kernel, rd_kreclaimable, KReclaimable); |
| 456 | |
| 457 | rrdset_done(st_mem_kernel); |
| 458 | } |
| 459 | |
| 460 | if(do_slab) { |
| 461 | static RRDSET *st_mem_slab = NULL; |
| 462 | static RRDDIM *rd_reclaimable = NULL, *rd_unreclaimable = NULL; |
| 463 | |
| 464 | if(unlikely(!st_mem_slab)) { |
| 465 | st_mem_slab = rrdset_create_localhost( |
| 466 | "mem" |
| 467 | , "slab" |
| 468 | , NULL |
| 469 | , "slab" |
| 470 | , NULL |
| 471 | , "Reclaimable Kernel Memory" |
| 472 | , "MiB" |
| 473 | , PLUGIN_PROC_NAME |
| 474 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 475 | , NETDATA_CHART_PRIO_MEM_SLAB |
| 476 | , update_every |
| 477 | , RRDSET_TYPE_STACKED |
| 478 | ); |
| 479 | |
| 480 | rd_reclaimable = rrddim_add(st_mem_slab, "reclaimable", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 481 | rd_unreclaimable = rrddim_add(st_mem_slab, "unreclaimable", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 482 | } |
| 483 | |
| 484 | rrddim_set_by_pointer(st_mem_slab, rd_reclaimable, SReclaimable); |
| 485 | rrddim_set_by_pointer(st_mem_slab, rd_unreclaimable, SUnreclaim); |
| 486 | rrdset_done(st_mem_slab); |
| 487 | } |
| 488 | |
| 489 | if (arl_hugepages_total->flags & ARL_ENTRY_FLAG_FOUND && HugePages_Total && |
| 490 | (do_hugepages == CONFIG_BOOLEAN_YES || do_hugepages == CONFIG_BOOLEAN_AUTO)) { |
| 491 | do_hugepages = CONFIG_BOOLEAN_YES; |
| 492 | |
| 493 | static RRDSET *st_mem_hugepages = NULL; |
| 494 | static RRDDIM *rd_used = NULL, *rd_free = NULL, *rd_rsvd = NULL, *rd_surp = NULL; |
| 495 | |
| 496 | if(unlikely(!st_mem_hugepages)) { |
| 497 | st_mem_hugepages = rrdset_create_localhost( |
| 498 | "mem" |
| 499 | , "hugepages" |
| 500 | , NULL |
| 501 | , "hugepages" |
| 502 | , NULL |
| 503 | , "Dedicated HugePages Memory" |
| 504 | , "MiB" |
| 505 | , PLUGIN_PROC_NAME |
| 506 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 507 | , NETDATA_CHART_PRIO_MEM_HUGEPAGES |
| 508 | , update_every |
| 509 | , RRDSET_TYPE_STACKED |
| 510 | ); |
| 511 | |
| 512 | rd_free = rrddim_add(st_mem_hugepages, "free", NULL, Hugepagesize, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 513 | rd_used = rrddim_add(st_mem_hugepages, "used", NULL, Hugepagesize, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 514 | rd_surp = rrddim_add(st_mem_hugepages, "surplus", NULL, Hugepagesize, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 515 | rd_rsvd = rrddim_add(st_mem_hugepages, "reserved", NULL, Hugepagesize, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 516 | } |
| 517 | |
| 518 | rrddim_set_by_pointer(st_mem_hugepages, rd_used, HugePages_Total - HugePages_Free - HugePages_Rsvd); |
| 519 | rrddim_set_by_pointer(st_mem_hugepages, rd_free, HugePages_Free); |
| 520 | rrddim_set_by_pointer(st_mem_hugepages, rd_rsvd, HugePages_Rsvd); |
| 521 | rrddim_set_by_pointer(st_mem_hugepages, rd_surp, HugePages_Surp); |
| 522 | rrdset_done(st_mem_hugepages); |
| 523 | } |
| 524 | |
| 525 | if (do_transparent_hugepages == CONFIG_BOOLEAN_YES || do_transparent_hugepages == CONFIG_BOOLEAN_AUTO) { |
| 526 | do_transparent_hugepages = CONFIG_BOOLEAN_YES; |
| 527 | |
| 528 | static RRDSET *st_mem_transparent_hugepages = NULL; |
| 529 | static RRDDIM *rd_anonymous = NULL, *rd_shared = NULL; |
| 530 | |
| 531 | if(unlikely(!st_mem_transparent_hugepages)) { |
| 532 | st_mem_transparent_hugepages = rrdset_create_localhost( |
| 533 | "mem" |
| 534 | , "thp" |
| 535 | , NULL |
| 536 | , "hugepages" |
| 537 | , NULL |
| 538 | , "Transparent HugePages Memory" |
| 539 | , "MiB" |
| 540 | , PLUGIN_PROC_NAME |
| 541 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 542 | , NETDATA_CHART_PRIO_MEM_HUGEPAGES + 1 |
| 543 | , update_every |
| 544 | , RRDSET_TYPE_STACKED |
| 545 | ); |
| 546 | |
| 547 | rd_anonymous = rrddim_add(st_mem_transparent_hugepages, "anonymous", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 548 | rd_shared = rrddim_add(st_mem_transparent_hugepages, "shmem", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 549 | } |
| 550 | |
| 551 | rrddim_set_by_pointer(st_mem_transparent_hugepages, rd_anonymous, AnonHugePages); |
| 552 | rrddim_set_by_pointer(st_mem_transparent_hugepages, rd_shared, ShmemHugePages); |
| 553 | rrdset_done(st_mem_transparent_hugepages); |
| 554 | |
| 555 | { |
| 556 | static RRDSET *st_mem_thp_details = NULL; |
| 557 | static RRDDIM *rd_shmem_pmd_mapped = NULL, *rd_file_huge_pages = NULL, *rd_file_pmd_mapped = NULL; |
| 558 | |
| 559 | if(unlikely(!st_mem_thp_details)) { |
| 560 | st_mem_thp_details = rrdset_create_localhost( |
| 561 | "mem" |
| 562 | , "thp_details" |
| 563 | , NULL |
| 564 | , "hugepages" |
| 565 | , NULL |
| 566 | , "Details of Transparent HugePages Usage" |
| 567 | , "MiB" |
| 568 | , PLUGIN_PROC_NAME |
| 569 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 570 | , NETDATA_CHART_PRIO_MEM_HUGEPAGES_DETAILS |
| 571 | , update_every |
| 572 | , RRDSET_TYPE_LINE |
| 573 | ); |
| 574 | |
| 575 | rd_shmem_pmd_mapped = rrddim_add(st_mem_thp_details, "shmem_pmd", "ShmemPmdMapped", 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 576 | rd_file_huge_pages = rrddim_add(st_mem_thp_details, "file", "FileHugePages", 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 577 | rd_file_pmd_mapped = rrddim_add(st_mem_thp_details, "file_pmd", "FilePmdMapped", 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 578 | } |
| 579 | |
| 580 | rrddim_set_by_pointer(st_mem_thp_details, rd_shmem_pmd_mapped, ShmemPmdMapped); |
| 581 | rrddim_set_by_pointer(st_mem_thp_details, rd_file_huge_pages, FileHugePages); |
| 582 | rrddim_set_by_pointer(st_mem_thp_details, rd_file_pmd_mapped, FilePmdMapped); |
| 583 | rrdset_done(st_mem_thp_details); |
| 584 | } |
| 585 | } |
| 586 | |
| 587 | if(do_reclaiming != CONFIG_BOOLEAN_NO) { |
| 588 | static RRDSET *st_mem_reclaiming = NULL; |
| 589 | static RRDDIM *rd_active = NULL, *rd_inactive = NULL, |
| 590 | *rd_active_anon = NULL, *rd_inactive_anon = NULL, |
| 591 | *rd_active_file = NULL, *rd_inactive_file = NULL, |
| 592 | *rd_unevictable = NULL, *rd_mlocked = NULL; |
| 593 | |
| 594 | if(unlikely(!st_mem_reclaiming)) { |
| 595 | st_mem_reclaiming = rrdset_create_localhost( |
| 596 | "mem" |
| 597 | , "reclaiming" |
| 598 | , NULL |
| 599 | , "reclaiming" |
| 600 | , NULL |
| 601 | , "Memory Reclaiming" |
| 602 | , "MiB" |
| 603 | , PLUGIN_PROC_NAME |
| 604 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 605 | , NETDATA_CHART_PRIO_MEM_RECLAIMING |
| 606 | , update_every |
| 607 | , RRDSET_TYPE_LINE |
| 608 | ); |
| 609 | |
| 610 | rd_active = rrddim_add(st_mem_reclaiming, "active", "Active", 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 611 | rd_inactive = rrddim_add(st_mem_reclaiming, "inactive", "Inactive", 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 612 | rd_active_anon = rrddim_add(st_mem_reclaiming, "active_anon", "Active(anon)", 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 613 | rd_inactive_anon = rrddim_add(st_mem_reclaiming, "inactive_anon", "Inactive(anon)", 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 614 | rd_active_file = rrddim_add(st_mem_reclaiming, "active_file", "Active(file)", 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 615 | rd_inactive_file = rrddim_add(st_mem_reclaiming, "inactive_file", "Inactive(file)", 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 616 | rd_unevictable = rrddim_add(st_mem_reclaiming, "unevictable", "Unevictable", 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 617 | rd_mlocked = rrddim_add(st_mem_reclaiming, "mlocked", "Mlocked", 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 618 | } |
| 619 | |
| 620 | rrddim_set_by_pointer(st_mem_reclaiming, rd_active, Active); |
| 621 | rrddim_set_by_pointer(st_mem_reclaiming, rd_inactive, Inactive); |
| 622 | rrddim_set_by_pointer(st_mem_reclaiming, rd_active_anon, ActiveAnon); |
| 623 | rrddim_set_by_pointer(st_mem_reclaiming, rd_inactive_anon, InactiveAnon); |
| 624 | rrddim_set_by_pointer(st_mem_reclaiming, rd_active_file, ActiveFile); |
| 625 | rrddim_set_by_pointer(st_mem_reclaiming, rd_inactive_file, InactiveFile); |
| 626 | rrddim_set_by_pointer(st_mem_reclaiming, rd_unevictable, Unevictable); |
| 627 | rrddim_set_by_pointer(st_mem_reclaiming, rd_mlocked, Mlocked); |
| 628 | |
| 629 | rrdset_done(st_mem_reclaiming); |
| 630 | } |
| 631 | |
| 632 | if(do_high_low != CONFIG_BOOLEAN_NO && (arl_high_low->flags & ARL_ENTRY_FLAG_FOUND)) { |
| 633 | static RRDSET *st_mem_high_low = NULL; |
| 634 | static RRDDIM *rd_high_used = NULL, *rd_low_used = NULL; |
| 635 | static RRDDIM *rd_high_free = NULL, *rd_low_free = NULL; |
| 636 | |
| 637 | if(unlikely(!st_mem_high_low)) { |
| 638 | st_mem_high_low = rrdset_create_localhost( |
| 639 | "mem" |
| 640 | , "high_low" |
| 641 | , NULL |
| 642 | , "high_low" |
| 643 | , NULL |
| 644 | , "High and Low Used and Free Memory Areas" |
| 645 | , "MiB" |
| 646 | , PLUGIN_PROC_NAME |
| 647 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 648 | , NETDATA_CHART_PRIO_MEM_HIGH_LOW |
| 649 | , update_every |
| 650 | , RRDSET_TYPE_STACKED |
| 651 | ); |
| 652 | |
| 653 | rd_high_used = rrddim_add(st_mem_high_low, "high_used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 654 | rd_low_used = rrddim_add(st_mem_high_low, "low_used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 655 | rd_high_free = rrddim_add(st_mem_high_low, "high_free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 656 | rd_low_free = rrddim_add(st_mem_high_low, "low_free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 657 | } |
| 658 | |
| 659 | rrddim_set_by_pointer(st_mem_high_low, rd_high_used, HighTotal - HighFree); |
| 660 | rrddim_set_by_pointer(st_mem_high_low, rd_low_used, LowTotal - LowFree); |
| 661 | rrddim_set_by_pointer(st_mem_high_low, rd_high_free, HighFree); |
| 662 | rrddim_set_by_pointer(st_mem_high_low, rd_low_free, LowFree); |
| 663 | rrdset_done(st_mem_high_low); |
| 664 | } |
| 665 | |
| 666 | if (CmaTotal && do_cma != CONFIG_BOOLEAN_NO) { |
| 667 | do_cma = CONFIG_BOOLEAN_YES; |
| 668 | |
| 669 | static RRDSET *st_mem_cma = NULL; |
| 670 | static RRDDIM *rd_used = NULL, *rd_free = NULL; |
| 671 | |
| 672 | if(unlikely(!st_mem_cma)) { |
| 673 | st_mem_cma = rrdset_create_localhost( |
| 674 | "mem" |
| 675 | , "cma" |
| 676 | , NULL |
| 677 | , "cma" |
| 678 | , NULL |
| 679 | , "Contiguous Memory Allocator (CMA) Memory" |
| 680 | , "MiB" |
| 681 | , PLUGIN_PROC_NAME |
| 682 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 683 | , NETDATA_CHART_PRIO_MEM_CMA |
| 684 | , update_every |
| 685 | , RRDSET_TYPE_STACKED |
| 686 | ); |
| 687 | |
| 688 | rd_used = rrddim_add(st_mem_cma, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 689 | rd_free = rrddim_add(st_mem_cma, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 690 | } |
| 691 | |
| 692 | rrddim_set_by_pointer(st_mem_cma, rd_used, CmaTotal - CmaFree); |
| 693 | rrddim_set_by_pointer(st_mem_cma, rd_free, CmaFree); |
| 694 | rrdset_done(st_mem_cma); |
| 695 | } |
| 696 | |
| 697 | if(do_directmap != CONFIG_BOOLEAN_NO && |
| 698 | ((arl_directmap4k->flags & ARL_ENTRY_FLAG_FOUND) || |
| 699 | (arl_directmap2m->flags & ARL_ENTRY_FLAG_FOUND) || |
| 700 | (arl_directmap4m->flags & ARL_ENTRY_FLAG_FOUND) || |
| 701 | (arl_directmap1g->flags & ARL_ENTRY_FLAG_FOUND))) |
| 702 | { |
| 703 | static RRDSET *st_mem_directmap = NULL; |
| 704 | static RRDDIM *rd_4k = NULL, *rd_2m = NULL, *rd_1g = NULL, *rd_4m = NULL; |
| 705 | |
| 706 | if(unlikely(!st_mem_directmap)) { |
| 707 | st_mem_directmap = rrdset_create_localhost( |
| 708 | "mem" |
| 709 | , "directmaps" |
| 710 | , NULL |
| 711 | , "overview" |
| 712 | , NULL |
| 713 | , "Direct Memory Mappings" |
| 714 | , "MiB" |
| 715 | , PLUGIN_PROC_NAME |
| 716 | , PLUGIN_PROC_MODULE_MEMINFO_NAME |
| 717 | , NETDATA_CHART_PRIO_MEM_DIRECTMAP |
| 718 | , update_every |
| 719 | , RRDSET_TYPE_STACKED |
| 720 | ); |
| 721 | |
| 722 | if(arl_directmap4k->flags & ARL_ENTRY_FLAG_FOUND) |
| 723 | rd_4k = rrddim_add(st_mem_directmap, "4k", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 724 | |
| 725 | if(arl_directmap2m->flags & ARL_ENTRY_FLAG_FOUND) |
| 726 | rd_2m = rrddim_add(st_mem_directmap, "2m", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 727 | |
| 728 | if(arl_directmap4m->flags & ARL_ENTRY_FLAG_FOUND) |
| 729 | rd_4m = rrddim_add(st_mem_directmap, "4m", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 730 | |
| 731 | if(arl_directmap1g->flags & ARL_ENTRY_FLAG_FOUND) |
| 732 | rd_1g = rrddim_add(st_mem_directmap, "1g", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 733 | } |
| 734 | |
| 735 | if(rd_4k) |
| 736 | rrddim_set_by_pointer(st_mem_directmap, rd_4k, DirectMap4k); |
| 737 | |
| 738 | if(rd_2m) |
| 739 | rrddim_set_by_pointer(st_mem_directmap, rd_2m, DirectMap2M); |
| 740 | |
| 741 | if(rd_4m) |
| 742 | rrddim_set_by_pointer(st_mem_directmap, rd_4m, DirectMap4M); |
| 743 | |
| 744 | if(rd_1g) |
| 745 | rrddim_set_by_pointer(st_mem_directmap, rd_1g, DirectMap1G); |
| 746 | |
| 747 | rrdset_done(st_mem_directmap); |
| 748 | } |
| 749 | |
| 750 | return 0; |
| 751 | } |