typedef long (*uk_alloc_getpsize_func_t)
(struct uk_alloc *a);
+#if CONFIG_LIBUKALLOC_IFSTATS
+struct uk_alloc_stats {
+ size_t last_alloc_size; /* size of the last allocation */
+ size_t max_alloc_size; /* biggest satisfied allocation size */
+ size_t min_alloc_size; /* smallest satisfied allocation size */
+
+ uint64_t tot_nb_allocs; /* total number of satisfied allocations */
+ uint64_t tot_nb_frees; /* total number of satisfied free operations */
+ uint64_t cur_nb_allocs; /* current number of active allocations */
+ uint64_t max_nb_allocs; /* maximum number of active allocations */
+
+ size_t cur_mem_use; /* current used memory by allocations */
+ size_t max_mem_use; /* maximum amount of memory used by allocations */
+
+ uint64_t nb_enomem; /* number of times failing allocation requests */
+};
+#endif /* CONFIG_LIBUKALLOC_IFSTATS */
+
struct uk_alloc {
/* memory allocation */
uk_alloc_malloc_func_t malloc;
/* optional interface */
uk_alloc_addmem_func_t addmem;
+#if CONFIG_LIBUKALLOC_IFSTATS
+ struct uk_alloc_stats _stats;
+#endif
+
/* internal */
struct uk_alloc *next;
int8_t priv[];
unsigned long uk_alloc_pavailmem_total(void);
+#if CONFIG_LIBUKALLOC_IFSTATS
+/*
+ * Memory allocation statistics
+ */
+void uk_alloc_stats_get(struct uk_alloc *a, struct uk_alloc_stats *dst);
+#endif /* CONFIG_LIBUKALLOC_IFSTATS */
+
#ifdef __cplusplus
}
#endif
long uk_alloc_pavailmem_compat(struct uk_alloc *a);
long uk_alloc_pmaxalloc_compat(struct uk_alloc *a);
+#if CONFIG_LIBUKALLOC_IFSTATS
+#include <string.h>
+#include <uk/preempt.h>
+
+#if CONFIG_LIBUKALLOC_IFSTATS_GLOBAL
+extern struct uk_alloc_stats _uk_alloc_stats_global;
+#endif /* CONFIG_LIBUKALLOC_IFSTATS_GLOBAL */
+
+/* NOTE: Please do not use this function directly */
+static inline void _uk_alloc_stats_refresh_minmax(struct uk_alloc_stats *stats)
+{
+ if (stats->cur_nb_allocs > stats->max_nb_allocs)
+ stats->max_nb_allocs = stats->cur_nb_allocs;
+
+ if (stats->cur_mem_use > stats->max_mem_use)
+ stats->max_mem_use = stats->cur_mem_use;
+
+ if (stats->last_alloc_size) {
+ /* Force storing the minimum allocation size
+ * with the first allocation request
+ */
+ if ((stats->tot_nb_allocs == 1)
+ || (stats->last_alloc_size < stats->min_alloc_size))
+ stats->min_alloc_size = stats->last_alloc_size;
+ if (stats->last_alloc_size > stats->max_alloc_size)
+ stats->max_alloc_size = stats->last_alloc_size;
+ }
+}
+
+/* NOTE: Please do not use this function directly */
+static inline void _uk_alloc_stats_count_alloc(struct uk_alloc_stats *stats,
+ void *ptr, size_t size)
+{
+ /* TODO: SMP safety */
+ uk_preempt_disable();
+ if (likely(ptr)) {
+ stats->tot_nb_allocs++;
+
+ stats->cur_nb_allocs++;
+ stats->cur_mem_use += size;
+ stats->last_alloc_size = size;
+ _uk_alloc_stats_refresh_minmax(stats);
+ } else {
+ stats->nb_enomem++;
+ }
+ uk_preempt_enable();
+}
+
+/* NOTE: Please do not use this function directly */
+static inline void _uk_alloc_stats_count_free(struct uk_alloc_stats *stats,
+ void *ptr, size_t size)
+{
+ /* TODO: SMP safety */
+ uk_preempt_disable();
+ if (likely(ptr)) {
+ stats->tot_nb_frees++;
+
+ stats->cur_nb_allocs--;
+ stats->cur_mem_use -= size;
+ _uk_alloc_stats_refresh_minmax(stats);
+ }
+ uk_preempt_enable();
+}
+
+/*
+ * The following macros should be used to instrument an allocator for
+ * statistics:
+ */
+/* NOTE: If ptr is NULL, an ENOMEM event is counted */
+#define uk_alloc_stats_count_alloc(a, ptr, size) \
+ _uk_alloc_stats_count_alloc(&((a)->_stats), \
+ (ptr), (size))
+#define uk_alloc_stats_count_palloc(a, ptr, num_pages) \
+ uk_alloc_stats_count_alloc((a), (ptr), \
+ ((size_t) (num_pages)) << __PAGE_SHIFT)
+
+#define uk_alloc_stats_count_enomem(a, size) \
+ uk_alloc_stats_count_alloc((a), NULL, (size))
+#define uk_alloc_stats_count_penomem(a, num_pages) \
+ uk_alloc_stats_count_enomem((a), \
+ ((size_t) (num_pages)) << __PAGE_SHIFT)
+
+/* Note: if ptr is NULL, nothing is counted */
+#define uk_alloc_stats_count_free(a, ptr, freed_size) \
+ _uk_alloc_stats_count_free(&((a)->_stats), \
+ (ptr), (freed_size))
+#define uk_alloc_stats_count_pfree(a, ptr, num_pages) \
+ uk_alloc_stats_count_free((a), (ptr), \
+ ((size_t) (num_pages)) << __PAGE_SHIFT)
+
+#define uk_alloc_stats_reset(a) \
+ memset(&(a)->_stats, 0, sizeof((a)->_stats))
+
+#else /* !CONFIG_LIBUKALLOC_IFSTATS */
+#define uk_alloc_stats_count_alloc(a, ptr, size) do {} while (0)
+#define uk_alloc_stats_count_palloc(a, ptr, num_pages) do {} while (0)
+#define uk_alloc_stats_count_enomem(a, size) do {} while (0)
+#define uk_alloc_stats_count_penomem(a, num_pages) do {} while (0)
+#define uk_alloc_stats_count_free(a, ptr, freed_size) do {} while (0)
+#define uk_alloc_stats_count_pfree(a, ptr, num_pages) do {} while (0)
+#define uk_alloc_stats_reset(a) do {} while (0)
+#endif /* !CONFIG_LIBUKALLOC_IFSTATS */
+
/* Shortcut for doing a registration of an allocator that does not implement
* palloc() or pfree()
*/
? uk_alloc_pmaxalloc_compat : NULL; \
(a)->addmem = (addmem_f); \
\
+ uk_alloc_stats_reset((a)); \
uk_alloc_register((a)); \
} while (0)
? uk_alloc_pmaxalloc_compat : NULL; \
(a)->addmem = (addmem_f); \
\
+ uk_alloc_stats_reset((a)); \
uk_alloc_register((a)); \
} while (0)
#endif
? uk_alloc_maxalloc_ifpages : NULL; \
(a)->addmem = (addmem_func); \
\
+ uk_alloc_stats_reset((a)); \
uk_alloc_register((a)); \
} while (0)
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Simon Kuenzer <simon.kuenzer@neclab.eu>
+ *
+ * Copyright (c) 2020, NEC Laboratories Europe GmbH, NEC Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <uk/alloc_impl.h>
+
+void uk_alloc_stats_get(struct uk_alloc *a,
+ struct uk_alloc_stats *dst)
+{
+ UK_ASSERT(a);
+ UK_ASSERT(dst);
+
+ uk_preempt_disable();
+ memcpy(dst, &a->_stats, sizeof(*dst));
+ uk_preempt_enable();
+}