Improve tracef/tracelog to use the stack for small strings
authorNorbert Lange <nolange79@gmail.com>
Mon, 1 Aug 2022 14:35:24 +0000 (16:35 +0200)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Mon, 1 Aug 2022 15:07:02 +0000 (11:07 -0400)
Support two common cases, one being that the resulting message is
small enough to fit into a on-stack buffer.
The seconds being the common 'printf("%s", "Message")' scheme.

Unfortunately, iterating a va_list is destructive,
so it has to be copied before calling vprintf.

The implementation was moved to a separate file,
used by both tracef.c and tracelog.c.

Signed-off-by: Norbert Lange <nolange79@gmail.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
src/common/tracer.h
src/lib/lttng-ust/tracef.c
src/lib/lttng-ust/tracelog-internal.h [new file with mode: 0644]
src/lib/lttng-ust/tracelog.c

index 2affd6ab37e40fe553e0ce0a50f8e6c4dcf16653..8e18c9b5874903243c972103dc878d7f16817028 100644 (file)
@@ -26,6 +26,8 @@
 #define LTTNG_RFLAG_EXTENDED           RING_BUFFER_RFLAG_END
 #define LTTNG_RFLAG_END                        (LTTNG_RFLAG_EXTENDED << 1)
 
+#define LTTNG_TRACE_PRINTF_BUFSIZE     512
+
 /*
  * LTTng client type enumeration. Used by the consumer to map the
  * callbacks from its own address space.
index c05c781199f8235a62972a3e8969dec5fccf5594..92911e1dac2f39a1de7e40c7413170b38dc237bd 100644 (file)
@@ -7,6 +7,7 @@
 #define _LGPL_SOURCE
 #include <stdio.h>
 #include "common/macros.h"
+#include "common/tracer.h"
 
 /* The tracepoint definition is public, but the provider definition is hidden. */
 #define LTTNG_UST_TRACEPOINT_PROVIDER_HIDDEN_DEFINITION
 #define LTTNG_UST_TRACEPOINT_DEFINE
 #include "lttng-ust-tracef-provider.h"
 
-static inline
-void lttng_ust___vtracef(const char *fmt, va_list ap)
-       __attribute__((always_inline, format(printf, 1, 0)));
-static inline
-void lttng_ust___vtracef(const char *fmt, va_list ap)
-{
-       char *msg;
-       const int len = vasprintf(&msg, fmt, ap);
-
-       /* len does not include the final \0 */
-       if (len < 0)
-               goto end;
-       lttng_ust_tracepoint_cb_lttng_ust_tracef___event(msg, len,
-               LTTNG_UST_CALLER_IP());
-       free(msg);
-end:
-       return;
-}
+#include "tracelog-internal.h"
 
 void lttng_ust__vtracef(const char *fmt, va_list ap)
        __attribute__((format(printf, 1, 0)));
 void lttng_ust__vtracef(const char *fmt, va_list ap)
 {
-       lttng_ust___vtracef(fmt, ap);
+       LTTNG_UST_TRACELOG_VALIST(fmt, ap,
+               lttng_ust_tracepoint_cb_lttng_ust_tracef___event,
+               msg, len, LTTNG_UST_CALLER_IP());
 }
 
 void lttng_ust__tracef(const char *fmt, ...)
        __attribute__((format(printf, 1, 2)));
 void lttng_ust__tracef(const char *fmt, ...)
 {
-       va_list ap;
-
-       va_start(ap, fmt);
-       lttng_ust___vtracef(fmt, ap);
-       va_end(ap);
+       LTTNG_UST_TRACELOG_VARARG(fmt,
+               lttng_ust_tracepoint_cb_lttng_ust_tracef___event,
+               msg, len, LTTNG_UST_CALLER_IP());
 }
diff --git a/src/lib/lttng-ust/tracelog-internal.h b/src/lib/lttng-ust/tracelog-internal.h
new file mode 100644 (file)
index 0000000..e119744
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2013-2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2021 Norbert Lange <nolange79@gmail.com>
+ *
+ * Shared helper macro for tracelog and tracef.
+ */
+
+#define LTTNG_UST_TRACELOG_VARARG(fmt, callback, ...) \
+       do { \
+               char local_buf[LTTNG_TRACE_PRINTF_BUFSIZE]; \
+               char *alloc_buff = NULL, *msg = local_buf; \
+               size_t len = 0; \
+               va_list ap; \
+\
+               if (caa_unlikely(fmt[0] == '%' && fmt[1] == 's' && fmt[2] == '\0')) { \
+                       va_start(ap, fmt); \
+                       msg = va_arg(ap, char *); \
+                       va_end(ap); \
+                       len = strlen(msg); \
+               } else { \
+                       size_t buflen = sizeof(local_buf); \
+                       int ret; \
+\
+                       /* On-stack buffer attempt */ \
+                       va_start(ap, fmt); \
+                       ret = vsnprintf(msg, buflen, fmt, ap); \
+                       va_end(ap); \
+                       if (caa_unlikely(ret < 0)) \
+                               break; \
+                       len = (size_t)ret; \
+\
+                       if (caa_unlikely(len >= sizeof(local_buf))) { \
+                               buflen = len + 1; \
+                               alloc_buff = (char *)malloc(buflen); \
+                               if (!alloc_buff) \
+                                       goto end; \
+                               msg = alloc_buff; \
+                               va_start(ap, fmt); \
+                               ret = vsnprintf(msg, buflen, fmt, ap); \
+                               va_end(ap); \
+                               lttng_ust_runtime_bug_on(ret < 0 || (size_t)ret != buflen - 1); \
+                               len = (size_t)ret; \
+                       } \
+               } \
+\
+               callback(__VA_ARGS__); \
+end: \
+               /* Don't call a potentially instrumented forbidden free needlessly. */ \
+               if (caa_unlikely(alloc_buff)) \
+                       free(alloc_buff); \
+       } while(0)
+
+#define LTTNG_UST_TRACELOG_VALIST(fmt, ap, callback, ...) \
+       do { \
+               char local_buf[LTTNG_TRACE_PRINTF_BUFSIZE]; \
+               char *alloc_buff = NULL, *msg = local_buf; \
+               size_t len = 0; \
+\
+               if (caa_unlikely(fmt[0] == '%' && fmt[1] == 's' && fmt[2] == '\0')) { \
+                       msg = va_arg(ap, char *); \
+                       len = strlen(msg); \
+               } else { \
+                       size_t buflen = sizeof(local_buf); \
+                       va_list ap2; \
+                       int ret; \
+\
+                       va_copy(ap2, ap); \
+                       ret = vsnprintf(msg, buflen, fmt, ap2); \
+                       va_end(ap2); \
+                       if (caa_unlikely(ret < 0)) \
+                               break; \
+                       len = (size_t)ret; \
+\
+                       if (caa_unlikely(len >= sizeof(local_buf))) { \
+                               buflen = len + 1; \
+                               alloc_buff = (char *)malloc(buflen); \
+                               if (!alloc_buff) \
+                                       goto end; \
+                               msg = alloc_buff; \
+                               ret = vsnprintf(msg, buflen, fmt, ap); \
+                               lttng_ust_runtime_bug_on(ret < 0 || (size_t)ret != buflen - 1); \
+                               len = (size_t)ret; \
+                       } \
+               } \
+\
+               callback(__VA_ARGS__); \
+end: \
+               /* Don't call a potentially instrumented forbidden free needlessly. */ \
+               if (caa_unlikely(alloc_buff)) \
+                       free(alloc_buff); \
+       } while (0)
index 8147d7a339abc9383ba31e4816779811c0efaa36..bd38032cba31d30654bbc4a67a0d7bcc76030bab 100644 (file)
@@ -7,6 +7,7 @@
 #define _LGPL_SOURCE
 #include <stdio.h>
 #include "common/macros.h"
+#include "common/tracer.h"
 
 /* The tracepoint definition is public, but the provider definition is hidden. */
 #define LTTNG_UST_TRACEPOINT_PROVIDER_HIDDEN_DEFINITION
 #define LTTNG_UST_TRACEPOINT_DEFINE
 #include "lttng-ust-tracelog-provider.h"
 
+#include "tracelog-internal.h"
+
 #define LTTNG_UST_TRACELOG_CB(level) \
-       static inline \
-       void lttng_ust___vtracelog_##level(const char *file, \
-                       int line, const char *func, \
-                       const char *fmt, va_list ap) \
-               __attribute__((always_inline, format(printf, 4, 0))); \
-       \
-       static inline \
-       void lttng_ust___vtracelog_##level(const char *file, \
-                       int line, const char *func, \
-                       const char *fmt, va_list ap) \
-       { \
-               char *msg; \
-               const int len = vasprintf(&msg, fmt, ap); \
-               \
-               /* len does not include the final \0 */ \
-               if (len < 0) \
-                       goto end; \
-               lttng_ust_tracepoint_cb_lttng_ust_tracelog___##level(file, \
-                       line, func, msg, len, \
-                       LTTNG_UST_CALLER_IP()); \
-               free(msg); \
-       end: \
-               return; \
-       } \
-       \
        void lttng_ust__vtracelog_##level(const char *file, \
                        int line, const char *func, \
                        const char *fmt, va_list ap) \
@@ -53,7 +31,9 @@
                        int line, const char *func, \
                        const char *fmt, va_list ap) \
        { \
-               lttng_ust___vtracelog_##level(file, line, func, fmt, ap); \
+               LTTNG_UST_TRACELOG_VALIST(fmt, ap, \
+                       lttng_ust_tracepoint_cb_lttng_ust_tracelog___##level, \
+                       file, line, func, msg, len, LTTNG_UST_CALLER_IP()); \
        } \
        \
        void lttng_ust__tracelog_##level(const char *file, \
                        int line, const char *func, \
                        const char *fmt, ...) \
        { \
-               va_list ap; \
-               \
-               va_start(ap, fmt); \
-               lttng_ust___vtracelog_##level(file, line, func, fmt, ap); \
-               va_end(ap); \
+               LTTNG_UST_TRACELOG_VARARG(fmt, \
+                       lttng_ust_tracepoint_cb_lttng_ust_tracelog___##level, \
+                       file, line, func, msg, len, LTTNG_UST_CALLER_IP()); \
        }
 
 LTTNG_UST_TRACELOG_CB(LTTNG_UST_TRACEPOINT_LOGLEVEL_EMERG)
This page took 0.027729 seconds and 4 git commands to generate.