From a850ee45f189dc4afd935f967ee7e5fa4168a2d9 Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Sun, 31 Jan 2016 20:07:20 +0100 Subject: degesch: optimize buffer memory usage We have approximately 5 formatter_items per buffer_line. Let's assume we're on a 64-bit machine. Then there were (5 * 2) + 3 useless pointers (104 bytes) as well as 5 * (4 + 4) = 40 bytes of wasted space because of needless padding. That's 144 bytes already. Compared to that, this change adds 16 bytes of overhead for an array sentinel, i.e. 128B less. With a limit of 1000 lines per buffer, we've saved ~128kB per buffer on completely useless data, and code complexity stays roughly the same. All in all, memory usage for buffers should be about 50% lower. --- NEWS | 2 ++ degesch.c | 74 +++++++++++++++++++++++++++++++++------------------------------ 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/NEWS b/NEWS index f19388c..60e07d3 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,8 @@ * degesch: backlog limit was made configurable + * degesch: optimize buffer memory usage + * kike: add support for IRCv3.2 server-time * Remote addresses are now resolved asynchronously diff --git a/degesch.c b/degesch.c index 26f0065..93d9316 100644 --- a/degesch.c +++ b/degesch.c @@ -968,6 +968,7 @@ REF_COUNTABLE_METHODS (channel) enum formatter_item_type { + FORMATTER_ITEM_END, ///< Sentinel value for arrays FORMATTER_ITEM_TEXT, ///< Text FORMATTER_ITEM_ATTR, ///< Formatting attributes FORMATTER_ITEM_FG_COLOR, ///< Foreground color @@ -978,26 +979,16 @@ enum formatter_item_type struct formatter_item { - LIST_HEADER (struct formatter_item) - - enum formatter_item_type type; ///< Type of this item + enum formatter_item_type type : 16; ///< Type of this item + int attribute : 16; ///< Attribute ID int color; ///< Color - int attribute; ///< Attribute ID - char *text; ///< Either text or an attribute string + char *text; ///< String }; -static struct formatter_item * -formatter_item_new (void) -{ - struct formatter_item *self = xcalloc (1, sizeof *self); - return self; -} - static void -formatter_item_destroy (struct formatter_item *self) +formatter_item_free (struct formatter_item *self) { free (self->text); - free (self); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1008,7 +999,8 @@ struct formatter struct server *s; ///< Server struct formatter_item *items; ///< Items - struct formatter_item *items_tail; ///< Tail of items + size_t items_len; ///< Items used + size_t items_alloc; ///< Items allocated }; static void @@ -1018,13 +1010,16 @@ formatter_init (struct formatter *self, memset (self, 0, sizeof *self); self->ctx = ctx; self->s = s; + self->items = xcalloc (sizeof *self->items, (self->items_alloc = 16)); + self->items_len = 0; } static void formatter_free (struct formatter *self) { - LIST_FOR_EACH (struct formatter_item, iter, self->items) - formatter_item_destroy (iter); + for (size_t i = 0; i < self->items_len; i++) + formatter_item_free (&self->items[i]); + free (self->items); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1045,21 +1040,31 @@ struct buffer_line int flags; ///< Flags time_t when; ///< Time of the event - struct formatter formatter; ///< Line data + struct formatter_item items[]; ///< Line data }; +/// Create a new buffer line stealing all data from the provided formatter struct buffer_line * buffer_line_new (struct formatter *f) { - struct buffer_line *self = xcalloc (1, sizeof *self); - self->formatter = *f; + // We make space for one more item that gets initialized to all zeros, + // meaning FORMATTER_ITEM_END (because it's the first value in the enum) + size_t items_size = f->items_len * sizeof *f->items; + struct buffer_line *self = + xcalloc (1, sizeof *self + items_size + sizeof *self->items); + memcpy (self->items, f->items, items_size); + + // We've stolen pointers from the formatter, let's destroy it altogether + free (f->items); + memset (f, 0, sizeof *f); return self; } static void buffer_line_destroy (struct buffer_line *self) { - formatter_free (&self->formatter); + for (struct formatter_item *iter = self->items; iter->type; iter++) + formatter_item_free (iter); free (self); } @@ -2619,9 +2624,10 @@ formatter_add_item (struct formatter *self, struct formatter_item template_) if (template_.text) template_.text = xstrdup (template_.text); - struct formatter_item *item = formatter_item_new (); - *item = template_; - LIST_APPEND_WITH_TAIL (self->items, self->items_tail, item); + if (self->items_len == self->items_alloc) + self->items = xreallocarray + (self->items, sizeof *self->items, (self->items_alloc <<= 1)); + self->items[self->items_len++] = template_; } #define FORMATTER_ADD_ITEM(self, type_, ...) formatter_add_item ((self), \ @@ -2911,13 +2917,6 @@ formatter_add (struct formatter *self, const char *format, ...) va_end (ap); } -static void -formatter_add_from (struct formatter *self, struct formatter *other) -{ - for (struct formatter_item *iter = other->items; iter; iter = iter->next) - formatter_add_item (self, *iter); -} - static bool formatter_flush_attr (struct attribute_printer *state, struct formatter_item *item) @@ -2969,9 +2968,12 @@ formatter_flush (struct formatter *self, FILE *stream, bool raw_attributes) { if (!raw_attributes && !get_attribute_printer (stream)) { - LIST_FOR_EACH (struct formatter_item, iter, self->items) + for (size_t i = 0; i < self->items_len; i++) + { + struct formatter_item *iter = &self->items[i]; if (iter->type == FORMATTER_ITEM_TEXT) fputs (iter->text, stream); + } return; } @@ -2980,8 +2982,9 @@ formatter_flush (struct formatter *self, FILE *stream, bool raw_attributes) attribute_printer_reset (&state); int attribute_ignore = 0; - LIST_FOR_EACH (struct formatter_item, iter, self->items) + for (size_t i = 0; i < self->items_len; i++) { + struct formatter_item *iter = &self->items[i]; if (iter->type == FORMATTER_ITEM_TEXT) formatter_flush_text (self->ctx, iter->text, stream); else if (iter->type == FORMATTER_ITEM_IGNORE_ATTR) @@ -3051,7 +3054,9 @@ buffer_line_flush (struct buffer_line *line, struct formatter *f, FILE *output, if (flags & BUFFER_LINE_STATUS) formatter_add (f, " - "); if (flags & BUFFER_LINE_ERROR) formatter_add (f, "#a=!=#r ", ATTR_ERROR); - formatter_add_from (f, &line->formatter); + for (struct formatter_item *iter = line->items; iter->type; iter++) + formatter_add_item (f, *iter); + formatter_add (f, "\n"); formatter_flush (f, output, raw_attributes); formatter_free (f); @@ -3141,7 +3146,6 @@ log_formatter (struct app_context *ctx, if (!buffer) buffer = ctx->global_buffer; - // Move the formatter inside struct buffer_line *line = buffer_line_new (f); line->flags = flags; // TODO: allow providing custom time (IRCv3.2 server-time) -- cgit v1.2.3-70-g09d2