[PATCHES] Logging to multiple debug backends
Christof Schmitt
cs at samba.org
Mon Mar 16 14:54:26 MDT 2015
On Mon, Mar 16, 2015 at 11:56:06AM +0100, Volker Lendecke wrote:
> On Sat, Mar 14, 2015 at 02:52:05PM +1100, Martin Schwenke wrote:
> > The debug code is very heavily used so I would prematurely
> > optimise. :-) Instead of using an array of all possible backends in
> > debug_set_backends() and debug_backends_log(), I would suggest using a
> > doubly-linked list, and inserting the backends in reverse-sorted order
> > of priority. Then you only need to traverse the list as long as
> > msg_level <= log_level. This makes debug_set_backends() more expensive
> > but makes debug_backends_log() cheaper.
>
> If you *really* want to prematurely optimize, I would recommend splitting
> the array into two, just for cache locality. If you make it two arrays,
> one with full information and one with just what is required in the
> debug_backends_log for-loop, you should be able to squeeze 4 backends
> into 64 bytes. At that point I'd say the for-loop over all those 4
> backends comes at almost no cost. Most of it should be hidden behind
> loop unrolling and speculative execution. A linked list will very likely
> be much more expensive to chase through our 15 levels of cache these
> days. That together with the fact that we only enter debug_backends_log()
> when there is something to log, my gut feeling is that everything else
> will be much more expensive than walking 2 or 3 backends unnecessarily.
I started implementing a separate array, see the attached patch. So far
it compiles, but it is untested. Does that fit your idea?
If we agree that this is worthwhile, i will cleanup and squash the patch
and resubmit the patch series.
Christof
-------------- next part --------------
From 200186e312204b79a6a45e8e5edf3cd81f90d888 Mon Sep 17 00:00:00 2001
From: Christof Schmitt <cs at samba.org>
Date: Mon, 16 Mar 2015 13:50:33 -0700
Subject: [PATCH] introduce optimized array
---
lib/util/debug.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 64 insertions(+), 7 deletions(-)
diff --git a/lib/util/debug.c b/lib/util/debug.c
index e246945..9d6cf81 100644
--- a/lib/util/debug.c
+++ b/lib/util/debug.c
@@ -28,6 +28,7 @@
#include "close_low_fd.h"
#include "memory.h"
#include "samba_util.h" /* LIST_SEP */
+#include "tsort.h"
#include "debug.h"
/* define what facility to use for syslog */
@@ -230,10 +231,10 @@ static void debug_gpfs_log(int msg_level,
static struct debug_backend {
const char *name;
- int log_level;
- int new_log_level;
void (*reload)(bool enabled, bool prev_enabled, const char *prog_name);
void (*log)(int msg_level, const char *msg, const char *msg_no_nl);
+ int new_log_level;
+ int log_level;
} debug_backends[] = {
{
.name = "file",
@@ -270,6 +271,18 @@ static struct debug_backend {
#endif
};
+/*
+ * Optimized array for debug_backends_do_log(). The minimum information
+ * is kept for calling the logging backend, for the data to fit in a
+ * cacheline when possible. Entries are also kept in descending order
+ * of log level, so that the loop in debug_backends_do_log() can exit
+ * early.
+ */
+static struct debug_backend_log {
+ void (*log)(int msg_level, const char *msg, const char *msg_no_nl);
+ int log_level;
+} debug_backends_log[ARRAY_SIZE(debug_backends)];
+
static struct debug_backend *debug_find_backend(const char *name)
{
int i;
@@ -307,6 +320,25 @@ static void debug_backend_parse_token(char *tok)
}
/*
+ * Comparison for sorting by decreasing log level.
+ */
+static int debug_backends_compare(const void *data1, const void *data2)
+{
+ const struct debug_backend *b1 = data1;
+ const struct debug_backend *b2 = data2;
+
+ if (b1->log_level > b2->log_level) {
+ return -1;
+ }
+
+ if (b1->log_level < b2->log_level) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
* parse string "backend1[:loglevel1] backend2[:loglevel2] ... " and
* enable/disable backends accordingly
*/
@@ -342,6 +374,7 @@ static void debug_set_backends(const char *param)
*/
for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
struct debug_backend *b = &debug_backends[i];
+ struct debug_backend_log *bl = &debug_backends_log[i];
if (b->reload) {
bool enabled = b->new_log_level > -1;
@@ -350,10 +383,22 @@ static void debug_set_backends(const char *param)
b->reload(enabled, previously_enabled, state.prog_name);
}
b->log_level = b->new_log_level;
+
+ /*
+ * Update optimized array
+ */
+ bl->log = b->log;
+ bl->log_level = b->log_level;
}
+
+ /*
+ * Sort optimized array again
+ */
+ TYPESAFE_QSORT(debug_backends_log, ARRAY_SIZE(debug_backends_log),
+ debug_backends_compare);
}
-static void debug_backends_log(const char *msg, int msg_level)
+static void debug_backends_do_log(const char *msg, int msg_level)
{
char msg_no_nl[FORMAT_BUFR_SIZE];
int len = strlen(msg);
@@ -370,10 +415,18 @@ static void debug_backends_log(const char *msg, int msg_level)
memcpy(msg_no_nl, msg, len);
msg_no_nl[len] = '\0';
- for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
- if (msg_level <= debug_backends[i].log_level) {
- debug_backends[i].log(msg_level, msg, msg_no_nl);
+ for (i = 0; i < ARRAY_SIZE(debug_backends_log); i++) {
+ struct debug_backend_log *bl = &debug_backends_log[i];
+
+ if (msg_level > bl->log_level) {
+ /*
+ * Array is sorted by decreasing log level,
+ * all other entries can be skipped.
+ */
+ break;
}
+
+ bl->log(msg_level, msg, msg_no_nl);
}
}
@@ -733,6 +786,10 @@ static void debug_init(void)
debug_backends[i].log_level = -1;
debug_backends[i].new_log_level = -1;
}
+
+ for (i = 0; i < ARRAY_SIZE(debug_backends_log); i++) {
+ debug_backends_log[i].log_level = -1;
+ }
}
void debug_set_settings(struct debug_settings *settings,
@@ -1085,7 +1142,7 @@ static void Debug1(const char *msg)
}
break;
case DEBUG_FILE:
- debug_backends_log(msg, current_msg_level);
+ debug_backends_do_log(msg, current_msg_level);
break;
};
--
1.7.1
More information about the samba-technical
mailing list