@cryptotaxi247 / netdata-1 / commits / e2e008e4f

Reduce glibc fragmentation Part 2 (#19390)

* dictionary uses exclusively aral for allocations, except when the dictionary is variable sized * make all fixed size dictionaries use flag DICT_OPTION_FIXED_SIZE * memory accounting for rrd memory slots * use aral for extents * extent page sizes per KiB * test to see if 4KiB is better than 1KiB

Costa Tsaousis committed Jan 13, 2025 at 17:15 UTC e2e008e4fa7481686d620f86aa0f2f0564409987
23 files changed +114 -49
src/collectors/cups.plugin/cups_plugin.c
+1 -1
@@ -227,7 +227,7 @@ int main(int argc, char **argv) {
227
228 errno_clear();
229
230 - dict_dest_job_metrics = dictionary_create(DICT_OPTION_SINGLE_THREADED);
230 + dict_dest_job_metrics = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct job_metrics));
231
232 // ------------------------------------------------------------------------
233 // the main loop
src/collectors/debugfs.plugin/module-libsensors.c
+1 -1
@@ -1230,7 +1230,7 @@ void *libsensors_thread(void *ptr __maybe_unused) {
1230 }
1231 if(fp) fclose(fp);
1232
1233 - sensors_dict = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_SINGLE_THREADED);
1233 + sensors_dict = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_SINGLE_THREADED | DICT_OPTION_FIXED_SIZE, NULL, sizeof(SENSOR));
1234
1235 // preflight to check data collection latency
1236 {
src/collectors/diskspace.plugin/plugin_diskspace.c
+1 -1
@@ -332,7 +332,7 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
332 SIMPLE_PATTERN_EXACT,
333 true);
334
335 - dict_mountpoints = dictionary_create_advanced(DICT_OPTION_NONE, &dictionary_stats_category_collectors, 0);
335 + dict_mountpoints = dictionary_create_advanced(DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(struct mount_point_metadata));
336 dictionary_register_delete_callback(dict_mountpoints, mountpoint_delete_cb, NULL);
337 }
338
src/collectors/proc.plugin/sys_block_zram.c
+1 -1
@@ -268,7 +268,7 @@ int do_sys_block_zram(int update_every, usec_t dt) {
268 }
269 procfile_close(ff);
270
271 - devices = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED, &dictionary_stats_category_collectors, 0);
271 + devices = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(ZRAM_DEVICE));
272 device_count = init_devices(devices, update_every);
273 }
274
src/collectors/proc.plugin/sys_devices_pci_aer.c
+2 -2
@@ -42,7 +42,7 @@ static bool aer_value_conflict_callback(const DICTIONARY_ITEM *item __maybe_unus
42
43 static void aer_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
44 struct aer_entry *a = value;
45 - a->values = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
45 + a->values = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE|DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(struct aer_value));
46 dictionary_register_conflict_callback(a->values, aer_value_conflict_callback, NULL);
47 }
48
@@ -209,7 +209,7 @@ int do_proc_sys_devices_pci_aer(int update_every, usec_t dt __maybe_unused) {
209 if(!do_root_ports && !do_pci_slots)
210 return 1;
211
212 - aer_root = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
212 + aer_root = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(struct aer_entry));
213 dictionary_register_insert_callback(aer_root, aer_insert_callback, NULL);
214
215 AER_TYPE types = ((do_root_ports) ? (AER_ROOTPORT_TOTAL_ERR_COR|AER_ROOTPORT_TOTAL_ERR_FATAL) : 0) |
src/collectors/statsd.plugin/statsd.c
+8 -8
@@ -623,7 +623,7 @@ static inline void statsd_process_dictionary(STATSD_METRIC *m, const char *value
623 statsd_reset_metric(m);
624
625 if (unlikely(!m->dictionary.dict))
626 - m->dictionary.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
626 + m->dictionary.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC_DICTIONARY_ITEM));
627
628 if(unlikely(value_is_zinit(value))) {
629 // magic loading of metric, without affecting anything
@@ -2455,13 +2455,13 @@ void *statsd_main(void *ptr) {
2455 worker_register_job_name(WORKER_STATSD_FLUSH_DICTIONARIES, "dictionaries");
2456 worker_register_job_name(WORKER_STATSD_FLUSH_STATS, "statistics");
2457
2458 - statsd.gauges.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2459 - statsd.meters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2460 - statsd.counters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2461 - statsd.histograms.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2462 - statsd.dictionaries.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2463 - statsd.sets.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2464 - statsd.timers.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2458 + statsd.gauges.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2459 + statsd.meters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2460 + statsd.counters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2461 + statsd.histograms.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2462 + statsd.dictionaries.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2463 + statsd.sets.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2464 + statsd.timers.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2465
2466 dictionary_register_insert_callback(statsd.gauges.dict, dictionary_metric_insert_callback, &statsd.gauges);
2467 dictionary_register_insert_callback(statsd.meters.dict, dictionary_metric_insert_callback, &statsd.meters);
src/collectors/tc.plugin/plugin_tc.c
+2 -2
@@ -98,7 +98,7 @@ static bool tc_class_conflict_callback(const DICTIONARY_ITEM *item __maybe_unuse
98
99 static void tc_class_index_init(struct tc_device *d) {
100 if(!d->classes) {
101 - d->classes = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_SINGLE_THREADED, &dictionary_stats_category_collectors, 0);
101 + d->classes = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_SINGLE_THREADED | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(struct tc_class));
102
103 dictionary_register_delete_callback(d->classes, tc_class_free_callback, d);
104 dictionary_register_conflict_callback(d->classes, tc_class_conflict_callback, d);
@@ -111,7 +111,7 @@ static void tc_class_index_destroy(struct tc_device *d) {
111 }
112
113 static struct tc_class *tc_class_index_add(struct tc_device *d, struct tc_class *c) {
114 - return dictionary_set(d->classes, string2str(c->id), c, sizeof(*c));
114 + return dictionary_set(d->classes, string2str(c->id), c, sizeof(struct tc_class));
115 }
116
117 static void tc_class_index_del(struct tc_device *d, struct tc_class *c) {
src/daemon/dyncfg/dyncfg.c
+1 -1
@@ -161,7 +161,7 @@ static bool dyncfg_conflict_cb(const DICTIONARY_ITEM *item __maybe_unused, void
161
162 void dyncfg_init_low_level(bool load_saved) {
163 if(!dyncfg_globals.nodes) {
164 - dyncfg_globals.nodes = dictionary_create_advanced(DICT_OPTION_FIXED_SIZE | DICT_OPTION_DONT_OVERWRITE_VALUE, NULL, sizeof(DYNCFG));
164 + dyncfg_globals.nodes = dictionary_create_advanced(DICT_OPTION_FIXED_SIZE | DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_dyncfg, sizeof(DYNCFG));
165 dictionary_register_insert_callback(dyncfg_globals.nodes, dyncfg_insert_cb, NULL);
166 dictionary_register_react_callback(dyncfg_globals.nodes, dyncfg_react_cb, NULL);
167 dictionary_register_conflict_callback(dyncfg_globals.nodes, dyncfg_conflict_cb, NULL);
src/daemon/pulse/pulse-daemon-memory.c
+15
@@ -4,6 +4,16 @@
4 #include "pulse-daemon-memory.h"
5 #include "streaming/stream-replication-sender.h"
6
7 +static size_t rrd_slot_memory = 0;
8 +
9 +void rrd_slot_memory_added(size_t added) {
10 + __atomic_add_fetch(&rrd_slot_memory, added, __ATOMIC_RELAXED);
11 +}
12 +
13 +void rrd_slot_memory_removed(size_t added) {
14 + __atomic_sub_fetch(&rrd_slot_memory, added, __ATOMIC_RELAXED);
15 +}
16 +
17 #define dictionary_stats_memory_total(stats) \
18 ((stats).memory.dict + (stats).memory.values + (stats).memory.index)
19
@@ -38,6 +48,7 @@ void pulse_daemon_memory_do(bool extended) {
48 static RRDDIM *rd_workers = NULL;
49 static RRDDIM *rd_aral = NULL;
50 static RRDDIM *rd_judy = NULL;
51 + static RRDDIM *rd_slots = NULL;
52 static RRDDIM *rd_other = NULL;
53
54 if (unlikely(!st_memory)) {
@@ -79,6 +90,7 @@ void pulse_daemon_memory_do(bool extended) {
90 rd_workers = rrddim_add(st_memory, "workers", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
91 rd_aral = rrddim_add(st_memory, "aral", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
92 rd_judy = rrddim_add(st_memory, "judy", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
93 + rd_slots = rrddim_add(st_memory, "slots", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
94 rd_other = rrddim_add(st_memory, "other", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
95 }
96
@@ -172,6 +184,9 @@ void pulse_daemon_memory_do(bool extended) {
184 rrddim_set_by_pointer(st_memory, rd_judy,
185 (collected_number) judy_aral_structures());
186
187 + rrddim_set_by_pointer(st_memory, rd_slots,
188 + (collected_number)__atomic_load_n(&rrd_slot_memory, __ATOMIC_RELAXED));
189 +
190 rrddim_set_by_pointer(st_memory, rd_other,
191 (collected_number)dictionary_stats_memory_total(dictionary_stats_category_other));
192
src/daemon/pulse/pulse-daemon-memory.h
+3
@@ -26,4 +26,7 @@ extern struct netdata_buffers_statistics {
26 void pulse_daemon_memory_do(bool extended);
27 #endif
28
29 +void rrd_slot_memory_added(size_t added);
30 +void rrd_slot_memory_removed(size_t added);
31 +
32 #endif //NETDATA_PULSE_DAEMON_MEMORY_H
src/daemon/pulse/pulse-dictionary.c
+2
@@ -12,6 +12,7 @@ struct dictionary_stats dictionary_stats_category_rrdlabels = { .name = "labels"
12 struct dictionary_stats dictionary_stats_category_rrdhealth = { .name = "health" };
13 struct dictionary_stats dictionary_stats_category_functions = { .name = "functions" };
14 struct dictionary_stats dictionary_stats_category_replication = { .name = "replication" };
15 +struct dictionary_stats dictionary_stats_category_dyncfg = { .name = "dyncfg" };
16
17 #ifdef DICT_WITH_STATS
18 struct dictionary_categories {
@@ -64,6 +65,7 @@ struct dictionary_categories {
65 { .stats = &dictionary_stats_category_rrdhealth, },
66 { .stats = &dictionary_stats_category_functions, },
67 { .stats = &dictionary_stats_category_replication, },
68 + { .stats = &dictionary_stats_category_dyncfg, },
69 { .stats = &dictionary_stats_category_other, },
70
71 // terminator
src/daemon/pulse/pulse-dictionary.h
+1
@@ -14,6 +14,7 @@ extern struct dictionary_stats dictionary_stats_category_rrdlabels;
14 extern struct dictionary_stats dictionary_stats_category_rrdhealth;
15 extern struct dictionary_stats dictionary_stats_category_functions;
16 extern struct dictionary_stats dictionary_stats_category_replication;
17 +extern struct dictionary_stats dictionary_stats_category_dyncfg;
18
19 #if defined(PULSE_INTERNALS)
20 void pulse_dictionary_do(bool extended);
src/database/contexts/api_v2_contexts_alert_config.c
+1
@@ -131,5 +131,6 @@ int contexts_v2_alert_config_to_json(struct web_client *w, const char *config_ha
131 }
132 }
133
134 + dictionary_destroy(configs);
135 return ret;
136 }
src/database/engine/page.c
+27 -7
@@ -100,13 +100,23 @@ static size_t aral_sizes[] = {
100 sizeof(gorilla_writer_t),
101 sizeof(PGD),
102
103 - 512, 1024, 1536, 2048, 5 * 512, 6 * 512, 7 * 512,
104 - 4 * 1024, 8 * 1024, 12 * 1024, 16 * 1024, 20 * 1024,
105 - 24 * 1024, 28 * 1024, 32 * 1024, 36 * 1024, 40 * 1024,
106 - 44 * 1024, 48 * 1024, 52 * 1024, 56 * 1024, 60 * 1024,
107 - 64 * 1024, 68 * 1024, 72 * 1024, 76 * 1024, 80 * 1024,
108 - 84 * 1024, 88 * 1024, 92 * 1024, 96 * 1024, 100 * 1024,
109 - 104 * 1024, 108 * 1024, 112 * 1024, 116 * 1024, 120 * 1024,
103 + // per 512B
104 + 512, 1024, 1536, 2048, 5 * 512, 6 * 512, 7 * 512, 8 * 512, /* 9 * 512, */
105 +
106 + // per 1KiB
107 +// 5 * 1024, 6 * 1024, 7 * 1024, 8 * 1024, 9 * 1024, 10 * 1024, 11 * 1024,
108 +// 12 * 1024, 13 * 1024, 14 * 1024, 15 * 1024, 16 * 1024, 17 * 1024, 18 * 1024,
109 +// 19 * 1024, 20 * 1024, 21 * 1024, 22 * 1024, 23 * 1024, 24 * 1024, 25 * 1024,
110 +// 26 * 1024, 27 * 1024, 28 * 1024, 29 * 1024, 30 * 1024, 31 * 1024, 32 * 1024,
111 +
112 + // test to see if 4KiB has less overheads than 1KiB
113 + 8 * 1024, 12 * 1024, 16 * 1024, 20 * 1024, 24 * 1024, 28 * 1024, 32 * 1024,
114 +
115 + // per 4KiB
116 + 36 * 1024, 40 * 1024, 44 * 1024, 48 * 1024, 52 * 1024, 56 * 1024, 60 * 1024,
117 + 64 * 1024, 68 * 1024, 72 * 1024, 76 * 1024, 80 * 1024, 84 * 1024, 88 * 1024,
118 + 92 * 1024, 96 * 1024, 100 * 1024, 104 * 1024, 108 * 1024, 112 * 1024, 116 * 1024,
119 + 120 * 1024, 124 * 1024, 128 * 1024,
120 };
121 static ARAL **arals = NULL;
122
@@ -317,6 +327,16 @@ static size_t pgd_data_footprint(size_t size, size_t partition) {
327 return size;
328 }
329
330 +// ----------------------------------------------------------------------------
331 +
332 +void *dbengine_extent_alloc(size_t size) {
333 + return pgd_data_alloc(size, 0, false);
334 +}
335 +
336 +void dbengine_extent_free(void *extent, size_t size) {
337 + pgd_data_free(extent, size, 0);
338 +}
339 +
340 // ----------------------------------------------------------------------------
341 // management api
342
src/database/engine/page.h
+3
@@ -56,6 +56,9 @@ size_t pgd_append_point(PGD *pg,
56 void pgdc_reset(PGDC *pgdc, PGD *pgd, uint32_t position);
57 bool pgdc_get_next_point(PGDC *pgdc, uint32_t expected_position, STORAGE_POINT *sp);
58
59 +void *dbengine_extent_alloc(size_t size);
60 +void dbengine_extent_free(void *extent, size_t size);
61 +
62 #ifdef __cplusplus
63 }
64 #endif
src/database/engine/pdc.c
-2
@@ -1288,12 +1288,10 @@ void epdl_find_extent_and_populate_pages(struct rrdengine_instance *ctx, EPDL *e
1288 void *extent_data = datafile_extent_read(ctx, epdl->file, epdl->extent_offset, epdl->extent_size);
1289 if(extent_data != NULL) {
1290
1291 -#if defined(NETDATA_TRACE_ALLOCATIONS)
1291 void *tmp = dbengine_extent_alloc(epdl->extent_size);
1292 memcpy(tmp, extent_data, epdl->extent_size);
1293 datafile_extent_read_free(extent_data);
1294 extent_data = tmp;
1296 -#endif
1295
1296 if(worker)
1297 worker_is_busy(UV_EVENT_DBENGINE_EXTENT_CACHE_LOOKUP);
src/database/engine/rrdengine.c
-9
@@ -584,15 +584,6 @@ static inline struct rrdeng_cmd rrdeng_deq_cmd(bool from_worker) {
584
585 // ----------------------------------------------------------------------------
586
587 -void *dbengine_extent_alloc(size_t size) {
588 - void *extent = mallocz(size);
589 - return extent;
590 -}
591 -
592 -void dbengine_extent_free(void *extent, size_t size __maybe_unused) {
593 - freez(extent);
594 -}
595 -
587 static void journalfile_extent_build(struct rrdengine_instance *ctx, struct extent_io_descriptor *xt_io_descr) {
588 unsigned count, payload_length, descr_size, size_bytes;
589 void *buf;
src/database/engine/rrdengine.h
-3
@@ -470,9 +470,6 @@ static inline void ctx_last_flush_fileno_set(struct rrdengine_instance *ctx, uns
470
471 #define ctx_is_available_for_queries(ctx) (__atomic_load_n(&(ctx)->quiesce.enabled, __ATOMIC_RELAXED) == false && __atomic_load_n(&(ctx)->quiesce.exit_mode, __ATOMIC_RELAXED) == false)
472
473 -void *dbengine_extent_alloc(size_t size);
474 -void dbengine_extent_free(void *extent, size_t size);
475 -
473 bool rrdeng_ctx_tier_cap_exceeded(struct rrdengine_instance *ctx);
474 int init_rrd_files(struct rrdengine_instance *ctx);
475 void finalize_rrd_files(struct rrdengine_instance *ctx);
src/database/rrdset.c
+11 -4
@@ -34,13 +34,15 @@ static void rrdset_stream_send_chart_slot_release(RRDSET *st) {
34 spinlock_lock(&host->stream.snd.pluginsd_chart_slots.available.spinlock);
35
36 if(host->stream.snd.pluginsd_chart_slots.available.used >= host->stream.snd.pluginsd_chart_slots.available.size) {
37 - uint32_t old_size = host->stream.snd.pluginsd_chart_slots.available.size;
38 - uint32_t new_size = (old_size > 0) ? (old_size * 2) : 1024;
37 + uint32_t old_slots = host->stream.snd.pluginsd_chart_slots.available.size;
38 + uint32_t new_slots = (old_slots > 0) ? (old_slots * 2) : 1024;
39
40 host->stream.snd.pluginsd_chart_slots.available.array =
41 - reallocz(host->stream.snd.pluginsd_chart_slots.available.array, new_size * sizeof(uint32_t));
41 + reallocz(host->stream.snd.pluginsd_chart_slots.available.array, new_slots * sizeof(uint32_t));
42
43 - host->stream.snd.pluginsd_chart_slots.available.size = new_size;
43 + host->stream.snd.pluginsd_chart_slots.available.size = new_slots;
44 +
45 + rrd_slot_memory_added((new_slots - old_slots) * sizeof(uint32_t));
46 }
47
48 host->stream.snd.pluginsd_chart_slots.available.array[host->stream.snd.pluginsd_chart_slots.available.used++] =
@@ -51,6 +53,8 @@ static void rrdset_stream_send_chart_slot_release(RRDSET *st) {
53 }
54
55 void rrdhost_pluginsd_send_chart_slots_free(RRDHOST *host) {
56 + rrd_slot_memory_removed(host->stream.snd.pluginsd_chart_slots.available.size * sizeof(uint32_t));
57 +
58 spinlock_lock(&host->stream.snd.pluginsd_chart_slots.available.spinlock);
59 host->stream.snd.pluginsd_chart_slots.available.ignore = true;
60 freez(host->stream.snd.pluginsd_chart_slots.available.array);
@@ -95,6 +99,7 @@ void rrdset_pluginsd_receive_unslot_and_cleanup(RRDSET *st) {
99
100 rrdset_pluginsd_receive_unslot(st);
101
102 + rrd_slot_memory_removed(st->pluginsd.size * sizeof(struct pluginsd_rrddim));
103 freez(st->pluginsd.prd_array);
104 st->pluginsd.prd_array = NULL;
105 st->pluginsd.size = 0;
@@ -113,6 +118,8 @@ static void rrdset_pluginsd_receive_slots_initialize(RRDSET *st) {
118 }
119
120 void rrdhost_pluginsd_receive_chart_slots_free(RRDHOST *host) {
121 + rrd_slot_memory_removed(host->stream.rcv.pluginsd_chart_slots.size * sizeof(uint32_t));
122 +
123 spinlock_lock(&host->stream.rcv.pluginsd_chart_slots.spinlock);
124
125 if(host->stream.rcv.pluginsd_chart_slots.array) {
src/health/health_prototypes.c
+2 -2
@@ -288,7 +288,7 @@ void health_init_prototypes(void) {
288 if(health_globals.prototypes.dict)
289 return;
290
291 - health_globals.prototypes.dict = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
291 + health_globals.prototypes.dict = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_rrdhealth, sizeof(RRD_ALERT_PROTOTYPE));
292 dictionary_register_insert_callback(health_globals.prototypes.dict, health_prototype_insert_cb, NULL);
293 dictionary_register_conflict_callback(health_globals.prototypes.dict, health_prototype_conflict_cb, NULL);
294 dictionary_register_delete_callback(health_globals.prototypes.dict, health_prototype_delete_cb, NULL);
@@ -472,7 +472,7 @@ bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap, char **msg) {
472 // add it to the prototypes
473 dictionary_set_advanced(health_globals.prototypes.dict,
474 string2str(ap->config.name), string_strlen(ap->config.name),
475 - ap, sizeof(*ap),
475 + ap, sizeof(RRD_ALERT_PROTOTYPE),
476 NULL);
477
478 return true;
src/libnetdata/dictionary/dictionary.c
+28 -4
@@ -20,13 +20,36 @@ inline void dictionary_write_unlock(DICTIONARY *dict) {
20 ll_recursive_unlock(dict, DICTIONARY_LOCK_WRITE);
21 }
22
23 +// ----------------------------------------------------------------------------
24 +// ARAL for dict and hooks
25 +
26 +static ARAL *ar_dict = NULL;
27 +static ARAL *ar_hooks = NULL;
28 +
29 +static void dictionary_init_aral(void) {
30 + if(ar_dict && ar_hooks) return;
31 +
32 + static SPINLOCK spinlock = SPINLOCK_INITIALIZER;
33 + spinlock_lock(&spinlock);
34 +
35 + if(!ar_dict)
36 + ar_dict = aral_by_size_acquire(sizeof(DICTIONARY));
37 +
38 + if(!ar_hooks)
39 + ar_hooks = aral_by_size_acquire(sizeof(struct dictionary_hooks));
40 +
41 + spinlock_unlock(&spinlock);
42 +}
43 +
44 // ----------------------------------------------------------------------------
45 // callbacks registration
46
47 static inline void dictionary_hooks_allocate(DICTIONARY *dict) {
48 if(dict->hooks) return;
49
29 - dict->hooks = callocz(1, sizeof(struct dictionary_hooks));
50 + dictionary_init_aral();
51 +
52 + dict->hooks = aral_callocz(ar_hooks);
53 dict->hooks->links = 1;
54
55 DICTIONARY_STATS_PLUS_MEMORY(dict, 0, sizeof(struct dictionary_hooks), 0);
@@ -37,7 +60,7 @@ static inline size_t dictionary_hooks_free(DICTIONARY *dict) {
60
61 REFCOUNT links = __atomic_sub_fetch(&dict->hooks->links, 1, __ATOMIC_ACQUIRE);
62 if(links == 0) {
40 - freez(dict->hooks);
63 + aral_freez(ar_hooks, dict->hooks);
64 dict->hooks = NULL;
65
66 DICTIONARY_STATS_MINUS_MEMORY(dict, 0, sizeof(struct dictionary_hooks), 0);
@@ -268,7 +291,7 @@ static bool dictionary_free_all_resources(DICTIONARY *dict, size_t *mem, bool fo
291 if(dict->value_aral)
292 aral_by_size_release(dict->value_aral);
293
271 - freez(dict);
294 + aral_freez(ar_dict, dict);
295
296 internal_error(
297 false,
@@ -464,9 +487,10 @@ static bool api_is_name_good_with_trace(DICTIONARY *dict __maybe_unused, const c
487 // API - dictionary management
488
489 static DICTIONARY *dictionary_create_internal(DICT_OPTIONS options, struct dictionary_stats *stats, size_t fixed_size) {
490 + dictionary_init_aral();
491 cleanup_destroyed_dictionaries();
492
469 - DICTIONARY *dict = callocz(1, sizeof(DICTIONARY));
493 + DICTIONARY *dict = aral_callocz(ar_dict);
494 dict->options = options;
495 dict->stats = stats;
496
src/plugins.d/pluginsd_internals.h
+3
@@ -141,6 +141,7 @@ static inline void pluginsd_rrddim_put_to_slot(PARSER *parser, RRDSET *st, RRDDI
141 st->pluginsd.prd_array[i].id = NULL;
142 }
143
144 + rrd_slot_memory_added((wanted_size - st->pluginsd.size) * sizeof(struct pluginsd_rrddim));
145 st->pluginsd.size = wanted_size;
146 }
147
@@ -301,6 +302,8 @@ static inline void pluginsd_rrdset_cache_put_to_slot(PARSER *parser, RRDSET *st,
302
303 host->stream.rcv.pluginsd_chart_slots.size = new_slots;
304 spinlock_unlock(&host->stream.rcv.pluginsd_chart_slots.spinlock);
305 +
306 + rrd_slot_memory_added((new_slots - old_slots) * sizeof(uint32_t));
307 }
308
309 host->stream.rcv.pluginsd_chart_slots.array[slot - 1] = st;
src/streaming/stream-replication-sender.c
+1 -1
@@ -1286,7 +1286,7 @@ void replication_sender_delete_pending_requests(struct sender_state *sender) {
1286
1287 void replication_sender_init(struct sender_state *sender) {
1288 sender->replication.requests = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
1289 - NULL, sizeof(struct replication_request));
1289 + &dictionary_stats_category_replication, sizeof(struct replication_request));
1290
1291 dictionary_register_react_callback(sender->replication.requests, replication_request_react_callback, sender);
1292 dictionary_register_conflict_callback(sender->replication.requests, replication_request_conflict_callback, sender);