*
* @param[in] buffer to clear cursor of.
*/
-static inline CC_HINT(always_inline) void fr_strerror_clear(fr_log_buffer_t *buffer, bool clear_pools)
+static inline CC_HINT(always_inline) void fr_strerror_clear(fr_log_buffer_t *buffer)
{
- if (clear_pools) {
- talloc_free_children(buffer->pool_a);
- talloc_free_children(buffer->pool_b);
- }
- fr_dlist_talloc_init(&buffer->entries, fr_log_entry_t, list);
+ fr_dlist_clear(&buffer->entries);
+
}
/** Initialise thread local storage
*
* @return fr_buffer_t containing log messages.
*/
-static inline fr_log_buffer_t *fr_strerror_init(void)
+static fr_log_buffer_t *fr_strerror_init(void)
{
fr_log_buffer_t *buffer;
fr_thread_local_set_destructor(fr_strerror_buffer, _fr_logging_free, buffer);
- fr_strerror_clear(buffer, false);
+ fr_dlist_talloc_init(&buffer->entries, fr_log_entry_t, list);
}
return buffer;
* when we're using fr_strerror as an argument
* for another message.
*/
-static inline CC_HINT(always_inline) TALLOC_CTX *pool_alternate(fr_log_buffer_t *buffer)
+static inline CC_HINT(always_inline) TALLOC_CTX *pool_alt(fr_log_buffer_t *buffer)
{
if (buffer->pool == buffer->pool_a) {
buffer->pool = buffer->pool_b;
return buffer->pool;
}
-
return buffer->pool = buffer->pool_a;
}
-static inline CC_HINT(always_inline) void pool_free_alt(fr_log_buffer_t *buffer)
+static inline CC_HINT(always_inline) void pool_alt_free_children(fr_log_buffer_t *buffer)
{
if (buffer->pool == buffer->pool_a) {
talloc_free_children(buffer->pool_b);
*
* @hidecallergraph
*/
-static fr_log_entry_t *strerror_vprintf(char const *fmt, va_list ap)
+static inline CC_HINT(always_inline) fr_log_entry_t *strerror_vprintf(char const *fmt, va_list ap)
{
va_list ap_p;
fr_log_entry_t *entry;
* Clear any existing log messages
*/
if (!fmt) {
- fr_strerror_clear(buffer, true);
+ talloc_free_children(buffer->pool_a);
+ talloc_free_children(buffer->pool_b);
+ fr_strerror_clear(buffer);
return NULL;
}
- entry = talloc_zero(pool_alternate(buffer), fr_log_entry_t);
- if (!entry) {
+ entry = talloc(pool_alt(buffer), fr_log_entry_t);
+ if (unlikely(!entry)) {
oom:
fr_perror("Failed allocating memory for libradius error buffer");
return NULL;
va_copy(ap_p, ap);
entry->msg = fr_vasprintf(entry, fmt, ap_p);
va_end(ap_p);
- if (!entry->msg) goto oom;
+ if (unlikely(!entry->msg)) goto oom;
+ entry->subject = NULL;
+ entry->offset = 0;
- pool_free_alt(buffer);
- fr_strerror_clear(buffer, false);
+ pool_alt_free_children(buffer);
+ fr_strerror_clear(buffer);
fr_dlist_insert_tail(&buffer->entries, entry);
return entry;
*
* @hidecallergraph
*/
-static fr_log_entry_t *strerror_vprintf_push(fr_log_buffer_t *buffer, char const *fmt, va_list ap)
+static inline CC_HINT(always_inline)
+fr_log_entry_t *strerror_vprintf_push(fr_log_buffer_t *buffer, char const *fmt, va_list ap)
{
va_list ap_p;
fr_log_entry_t *entry;
*/
if (!fr_dlist_num_elements(&buffer->entries)) talloc_free_children(buffer->pool);
- entry = talloc_zero(pool_alternate(buffer), fr_log_entry_t);
- if (!entry) {
+ entry = talloc(pool_alt(buffer), fr_log_entry_t);
+ if (unlikely(!entry)) {
oom:
fr_perror("Failed allocating memory for libradius error buffer");
return NULL;
va_copy(ap_p, ap);
entry->msg = fr_vasprintf(entry, fmt, ap_p);
va_end(ap_p);
- if (!entry->msg) goto oom;
+ if (unlikely(!entry->msg)) goto oom;
+ entry->subject = NULL;
+ entry->offset = 0;
return entry;
}
fr_log_entry_t *entry;
buffer = fr_strerror_init();
- if (!buffer) return;
+ if (unlikely(!buffer)) return;
va_start(ap, fmt);
entry = strerror_vprintf_push(buffer, fmt, ap);
va_end(ap);
- if (!entry) return;
+ if (unlikely(!entry)) return;
fr_dlist_insert_tail(&buffer->entries, entry);
}
fr_log_entry_t *entry;
buffer = fr_strerror_init();
- if (!buffer) return;
+ if (unlikely(!buffer)) return;
va_start(ap, fmt);
entry = strerror_vprintf_push(buffer, fmt, ap);
va_end(ap);
- if (!entry) return;
+ if (unlikely(!entry)) return;
fr_dlist_insert_head(&buffer->entries, entry);
}
entry = strerror_vprintf(fmt, ap);
va_end(ap);
- if (!entry) return;
+ if (unlikely(!entry)) return;
entry->subject = talloc_strdup(entry, subject);
entry->offset = offset;
fr_log_buffer_t *buffer;
buffer = fr_strerror_init();
- if (!buffer) return;
+ if (unlikely(!buffer)) return;
va_start(ap, fmt);
entry = strerror_vprintf_push(buffer, fmt, ap);
va_end(ap);
- if (!entry) return;
+ if (unlikely(!entry)) return;
entry->subject = talloc_strdup(entry, subject);
entry->offset = offset;
fr_log_buffer_t *buffer;
buffer = fr_strerror_init();
- if (!buffer) return;
+ if (unlikely(!buffer)) return;
va_start(ap, fmt);
entry = strerror_vprintf_push(buffer, fmt, ap);
va_end(ap);
- if (!entry) return;
+ if (unlikely(!entry)) return;
entry->subject = talloc_strdup(entry, subject);
entry->offset = offset;
fr_log_buffer_t *buffer;
buffer = fr_strerror_init();
- if (!buffer) return NULL;
+ if (unlikely(!buffer)) return NULL;
/*
* Clear any existing log messages
*/
if (!msg) {
- fr_strerror_clear(buffer, true);
+ fr_strerror_clear(buffer);
+ talloc_free_children(buffer->pool_a);
+ talloc_free_children(buffer->pool_b);
return NULL;
}
- entry = talloc(pool_alternate(buffer), fr_log_entry_t);
- if (!entry) {
+ entry = talloc(pool_alt(buffer), fr_log_entry_t);
+ if (unlikely(!entry)) {
fr_perror("Failed allocating memory for libradius error buffer");
return NULL;
}
- *entry = (fr_log_entry_t) {
- .msg = msg
- };
+ /*
+ * For some reason this is significantly
+ * more efficient than a compound literal
+ * even though in the majority of cases
+ * compound literals and individual field
+ * assignments result in the same byte
+ * code.
+ */
+ entry->msg = msg;
+ entry->subject = NULL;
+ entry->offset = 0;
- pool_free_alt(buffer);
- fr_strerror_clear(buffer, false);
+ pool_alt_free_children(buffer);
+ fr_strerror_clear(buffer);
fr_dlist_insert_tail(&buffer->entries, entry);
return entry;
*/
if (!fr_dlist_num_elements(&buffer->entries)) talloc_free_children(buffer->pool);
- entry = talloc_zero(pool_alternate(buffer), fr_log_entry_t);
- if (!entry) {
+ entry = talloc(pool_alt(buffer), fr_log_entry_t);
+ if (unlikely(!entry)) {
fr_perror("Failed allocating memory for libradius error buffer");
return NULL;
}
+ /*
+ * For some reason this is significantly
+ * more efficient than a compound literal
+ * even though in the majority of cases
+ * compound literals and individual field
+ * assignments result in the same byte
+ * code.
+ */
entry->msg = msg;
+ entry->subject = NULL;
+ entry->offset = 0;
return entry;
}
if (!buffer) return;
entry = strerror_const_push(buffer, msg);
-
- if (!entry) return;
+ if (unlikely(!entry)) return;
fr_dlist_insert_tail(&buffer->entries, entry);
}
if (!buffer) return;
entry = strerror_const_push(buffer, msg);
-
- if (!entry) return;
+ if (unlikely(!entry)) return;
fr_dlist_insert_head(&buffer->entries, entry);
}
* Memory gets freed on next call to
* fr_strerror_printf or fr_strerror_printf_push.
*/
- fr_strerror_clear(buffer, false);
+ fr_strerror_clear(buffer);
return entry->msg;
}
* Memory gets freed on next call to
* fr_strerror_printf or fr_strerror_printf_push.
*/
- fr_strerror_clear(buffer, false);
+ fr_strerror_clear(buffer);
*subject = entry->subject;
*offset = entry->offset;
*/
#include <freeradius-devel/util/acutest.h>
#include <freeradius-devel/util/acutest_helpers.h>
+#include <freeradius-devel/util/time.h>
#include "strerror.c"
TEST_CHECK(error && (error[0] == '\0'));
}
+static void strerror_printf_benchmark(void)
+{
+ int i;
+ fr_time_t start, stop;
+ uint64_t rate;
+
+ fr_strerror_const("pre-allocate buffers");
+ fr_strerror();
+
+ start = fr_time();
+ for (i = 0; i < 100000; i++) {
+ fr_strerror_printf("I am a test %u string %u %s", i, i, "benchmark");
+ fr_strerror(); /* Clear */
+ }
+ stop = fr_time();
+
+ rate = (uint64_t)((float)NSEC / ((stop - start) / 100000));
+ printf("printf pop rate %" PRIu64 "\n", rate);
+
+ TEST_CHECK(rate > 400000);
+}
+
+
+static void strerror_const_benchmark(void)
+{
+ int i;
+ fr_time_t start, stop;
+ uint64_t rate;
+
+ fr_strerror_const("pre-allocate buffers");
+ fr_strerror();
+
+ start = fr_time();
+ for (i = 0; i < 100000; i++) {
+ fr_strerror_const("I am a test string");
+ fr_strerror(); /* Clear */
+ }
+ stop = fr_time();
+
+ rate = (uint64_t)((float)NSEC / ((stop - start) / 100000));
+ printf("const pop rate %" PRIu64 "\n", rate);
+
+ TEST_CHECK(rate > 10000000);
+}
+
+
TEST_LIST = {
{ "strerror_uninit", strerror_uninit },
{ "strerror_pop_uninit", strerror_pop_uninit },
{ "strerror_printf_push_append", strerror_printf_push_append },
{ "strerror_printf_push_append2", strerror_printf_push_append2 },
+ { "strerror_printf_benchmark", strerror_printf_benchmark },
+ { "strerror_const_benchmark", strerror_const_benchmark },
+
{ 0 }
};