| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #define PULSE_INTERNALS 1 |
| 4 | #include "pulse-aral.h" |
| 5 | |
| 6 | struct aral_info { |
| 7 | const char *name; |
| 8 | RRDSET *st_memory; |
| 9 | RRDDIM *rd_malloc_used, *rd_malloc_free, *rd_mmap_used, *rd_mmap_free, *rd_structures, *rd_padding; |
| 10 | |
| 11 | RRDSET *st_utilization; |
| 12 | RRDDIM *rd_utilization; |
| 13 | }; |
| 14 | |
| 15 | DEFINE_JUDYL_TYPED(ARAL_STATS, struct aral_info *); |
| 16 | |
| 17 | static struct { |
| 18 | SPINLOCK spinlock; |
| 19 | ARAL_STATS_JudyLSet idx; |
| 20 | } globals = { 0 }; |
| 21 | |
| 22 | void pulse_aral_register_statistics(struct aral_statistics *stats, const char *name) { |
| 23 | if(!name || !stats) |
| 24 | return; |
| 25 | |
| 26 | spinlock_lock(&globals.spinlock); |
| 27 | struct aral_info *ai = ARAL_STATS_GET(&globals.idx, (Word_t)stats); |
| 28 | if(!ai) { |
| 29 | ai = callocz(1, sizeof(struct aral_info)); |
| 30 | ai->name = strdupz(name); |
| 31 | ARAL_STATS_SET(&globals.idx, (Word_t)stats, ai); |
| 32 | } |
| 33 | spinlock_unlock(&globals.spinlock); |
| 34 | } |
| 35 | |
| 36 | void pulse_aral_unregister_statistics(struct aral_statistics *stats) { |
| 37 | spinlock_lock(&globals.spinlock); |
| 38 | struct aral_info *ai = ARAL_STATS_GET(&globals.idx, (Word_t)stats); |
| 39 | if(ai) { |
| 40 | ARAL_STATS_DEL(&globals.idx, (Word_t)stats); |
| 41 | freez((void *)ai->name); |
| 42 | freez(ai); |
| 43 | } |
| 44 | spinlock_unlock(&globals.spinlock); |
| 45 | } |
| 46 | |
| 47 | void pulse_aral_register(ARAL *ar, const char *name) { |
| 48 | if(!ar) return; |
| 49 | |
| 50 | if(!name) |
| 51 | name = aral_name(ar); |
| 52 | |
| 53 | struct aral_statistics *stats = aral_get_statistics(ar); |
| 54 | |
| 55 | pulse_aral_register_statistics(stats, name); |
| 56 | } |
| 57 | |
| 58 | void pulse_aral_unregister(ARAL *ar) { |
| 59 | if(!ar) return; |
| 60 | struct aral_statistics *stats = aral_get_statistics(ar); |
| 61 | pulse_aral_unregister_statistics(stats); |
| 62 | } |
| 63 | |
| 64 | void pulse_aral_init(void) { |
| 65 | pulse_aral_register_statistics(aral_by_size_statistics(), "by-size"); |
| 66 | pulse_aral_register_statistics(judy_aral_statistics(), "judy"); |
| 67 | pulse_aral_register_statistics(uuidmap_aral_statistics(), "uuidmap"); |
| 68 | } |
| 69 | |
| 70 | void pulse_aral_do(bool extended) { |
| 71 | if(!extended) return; |
| 72 | |
| 73 | spinlock_lock(&globals.spinlock); |
| 74 | Word_t s = 0; |
| 75 | for(struct aral_info *ai = ARAL_STATS_FIRST(&globals.idx, &s); |
| 76 | ai; |
| 77 | ai = ARAL_STATS_NEXT(&globals.idx, &s)) { |
| 78 | struct aral_statistics *stats = (void *)(uintptr_t)s; |
| 79 | if (!stats) |
| 80 | continue; |
| 81 | |
| 82 | size_t malloc_allocated_bytes = __atomic_load_n(&stats->malloc.allocated_bytes, __ATOMIC_RELAXED); |
| 83 | size_t malloc_used_bytes = __atomic_load_n(&stats->malloc.used_bytes, __ATOMIC_RELAXED); |
| 84 | if(malloc_used_bytes > malloc_allocated_bytes) |
| 85 | malloc_allocated_bytes = malloc_used_bytes; |
| 86 | size_t malloc_free_bytes = malloc_allocated_bytes - malloc_used_bytes; |
| 87 | |
| 88 | size_t mmap_allocated_bytes = __atomic_load_n(&stats->mmap.allocated_bytes, __ATOMIC_RELAXED); |
| 89 | size_t mmap_used_bytes = __atomic_load_n(&stats->mmap.used_bytes, __ATOMIC_RELAXED); |
| 90 | if(mmap_used_bytes > mmap_allocated_bytes) |
| 91 | mmap_allocated_bytes = mmap_used_bytes; |
| 92 | size_t mmap_free_bytes = mmap_allocated_bytes - mmap_used_bytes; |
| 93 | |
| 94 | size_t allocated_total = malloc_allocated_bytes + mmap_allocated_bytes; |
| 95 | size_t used_total = malloc_used_bytes + mmap_used_bytes; |
| 96 | |
| 97 | size_t structures_bytes = __atomic_load_n(&stats->structures.allocated_bytes, __ATOMIC_RELAXED); |
| 98 | |
| 99 | size_t padding_bytes = __atomic_load_n(&stats->malloc.padding_bytes, __ATOMIC_RELAXED) + |
| 100 | __atomic_load_n(&stats->mmap.padding_bytes, __ATOMIC_RELAXED); |
| 101 | |
| 102 | NETDATA_DOUBLE utilization; |
| 103 | if(allocated_total) |
| 104 | utilization = 100.0 * (NETDATA_DOUBLE)used_total / (NETDATA_DOUBLE)allocated_total; |
| 105 | else |
| 106 | utilization = 100.0; |
| 107 | |
| 108 | { |
| 109 | if (unlikely(!ai->st_memory)) { |
| 110 | char id[256]; |
| 111 | |
| 112 | snprintfz(id, sizeof(id), "aral_%s_memory", ai->name); |
| 113 | netdata_fix_chart_id(id); |
| 114 | |
| 115 | ai->st_memory = rrdset_create_localhost( |
| 116 | "netdata", |
| 117 | id, |
| 118 | NULL, |
| 119 | "ARAL", |
| 120 | "netdata.aral_memory", |
| 121 | "Array Allocator Memory Utilization", |
| 122 | "bytes", |
| 123 | "netdata", |
| 124 | "pulse", |
| 125 | 910000, |
| 126 | localhost->rrd_update_every, |
| 127 | RRDSET_TYPE_STACKED); |
| 128 | |
| 129 | rrdlabels_add(ai->st_memory->rrdlabels, "ARAL", ai->name, RRDLABEL_SRC_AUTO); |
| 130 | |
| 131 | ai->rd_malloc_free = rrddim_add(ai->st_memory, "malloc free", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 132 | ai->rd_mmap_free = rrddim_add(ai->st_memory, "mmap free", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 133 | ai->rd_malloc_used = rrddim_add(ai->st_memory, "malloc used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 134 | ai->rd_mmap_used = rrddim_add(ai->st_memory, "mmap used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 135 | ai->rd_structures = rrddim_add(ai->st_memory, "structures", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 136 | ai->rd_padding = rrddim_add(ai->st_memory, "padding", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 137 | } |
| 138 | |
| 139 | rrddim_set_by_pointer(ai->st_memory, ai->rd_malloc_used, (collected_number)malloc_used_bytes); |
| 140 | rrddim_set_by_pointer(ai->st_memory, ai->rd_malloc_free, (collected_number)malloc_free_bytes); |
| 141 | rrddim_set_by_pointer(ai->st_memory, ai->rd_mmap_used, (collected_number)mmap_used_bytes); |
| 142 | rrddim_set_by_pointer(ai->st_memory, ai->rd_mmap_free, (collected_number)mmap_free_bytes); |
| 143 | rrddim_set_by_pointer(ai->st_memory, ai->rd_structures, (collected_number)structures_bytes); |
| 144 | rrddim_set_by_pointer(ai->st_memory, ai->rd_padding, (collected_number)padding_bytes); |
| 145 | rrdset_done(ai->st_memory); |
| 146 | } |
| 147 | |
| 148 | { |
| 149 | if (unlikely(!ai->st_utilization)) { |
| 150 | char id[256]; |
| 151 | |
| 152 | snprintfz(id, sizeof(id), "aral_%s_utilization", ai->name); |
| 153 | netdata_fix_chart_id(id); |
| 154 | |
| 155 | ai->st_utilization = rrdset_create_localhost( |
| 156 | "netdata", |
| 157 | id, |
| 158 | NULL, |
| 159 | "ARAL", |
| 160 | "netdata.aral_utilization", |
| 161 | "Array Allocator Memory Utilization", |
| 162 | "%", |
| 163 | "netdata", |
| 164 | "pulse", |
| 165 | 910001, |
| 166 | localhost->rrd_update_every, |
| 167 | RRDSET_TYPE_LINE); |
| 168 | |
| 169 | rrdlabels_add(ai->st_utilization->rrdlabels, "ARAL", ai->name, RRDLABEL_SRC_AUTO); |
| 170 | |
| 171 | ai->rd_utilization = rrddim_add(ai->st_utilization, "utilization", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); |
| 172 | } |
| 173 | |
| 174 | rrddim_set_by_pointer(ai->st_utilization, ai->rd_utilization, (collected_number)(utilization * 1000.0)); |
| 175 | rrdset_done(ai->st_utilization); |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | spinlock_unlock(&globals.spinlock); |
| 180 | } |