Module: xenomai-3 Branch: next Commit: 20387bcddf5e4413e41770ce4043e632b33d0905 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=20387bcddf5e4413e41770ce4043e632b33d0905
Author: Philippe Gerum <r...@xenomai.org> Date: Sat May 19 11:18:53 2018 +0200 testsuite/smokey: add core heap test --- configure.ac | 1 + testsuite/smokey/Makefile.am | 1 + testsuite/smokey/memcheck/memcheck.c | 250 +++++++++++++------------- testsuite/smokey/memcheck/memcheck.h | 22 ++- testsuite/smokey/memory-coreheap/Makefile.am | 9 + testsuite/smokey/memory-coreheap/coreheap.c | 108 +++++++++++ 6 files changed, 267 insertions(+), 124 deletions(-) diff --git a/configure.ac b/configure.ac index b670206..6c94301 100644 --- a/configure.ac +++ b/configure.ac @@ -971,6 +971,7 @@ AC_CONFIG_FILES([ \ testsuite/smokey/tsc/Makefile \ testsuite/smokey/leaks/Makefile \ testsuite/smokey/memcheck/Makefile \ + testsuite/smokey/memory-coreheap/Makefile \ testsuite/smokey/memory-heapmem/Makefile \ testsuite/smokey/memory-tlsf/Makefile \ testsuite/smokey/memory-pshared/Makefile \ diff --git a/testsuite/smokey/Makefile.am b/testsuite/smokey/Makefile.am index d7a71fe..601331e 100644 --- a/testsuite/smokey/Makefile.am +++ b/testsuite/smokey/Makefile.am @@ -16,6 +16,7 @@ COBALT_SUBDIRS = \ fpu-stress \ iddp \ leaks \ + memory-coreheap \ memory-heapmem \ memory-tlsf \ memcheck \ diff --git a/testsuite/smokey/memcheck/memcheck.c b/testsuite/smokey/memcheck/memcheck.c index 7f97218..a33700f 100644 --- a/testsuite/smokey/memcheck/memcheck.c +++ b/testsuite/smokey/memcheck/memcheck.c @@ -24,27 +24,45 @@ struct chunk { enum pattern pattern; }; -struct runstats { - size_t heap_size; - size_t user_size; - size_t block_size; - int nrblocks; - long alloc_avg_ns; - long alloc_max_ns; - long free_avg_ns; - long free_max_ns; - int flags; - double overhead; - double fragmentation; - struct runstats *next; -}; - -static struct runstats *statistics; +static struct memcheck_stat *statistics; static int nrstats; static int max_results = 4; +#ifdef CONFIG_XENO_COBALT + +#include <sys/cobalt.h> + +static inline void breathe(int loops) +{ + struct timespec idle = { + .tv_sec = 0, + .tv_nsec = 300000, + }; + + /* + * There is not rt throttling over Cobalt, so we may need to + * keep the host kernel breathing by napping during the test + * sequences. + */ + if ((loops % 1000) == 0) + __RT(clock_nanosleep(CLOCK_MONOTONIC, 0, &idle, NULL)); +} + +static inline void harden(void) +{ + cobalt_thread_harden(); +} + +#else + +static inline void breathe(int loops) { } + +static inline void harden(void) { } + +#endif + static inline long diff_ts(struct timespec *left, struct timespec *right) { return (long long)(left->tv_sec - right->tv_sec) * ONE_BILLION @@ -69,6 +87,7 @@ static void random_shuffle(void *vbase, size_t nmemb, const size_t size) double u; for(j = nmemb; j > 0; j--) { + breathe(j); u = (double)random() / RAND_MAX; k = (unsigned int)(j * u) + 1; if (j == k) @@ -88,37 +107,39 @@ static void random_shuffle(void *vbase, size_t nmemb, const size_t size) static int sort_by_heap_size(const void *l, const void *r) { - const struct runstats *ls = l, *rs = r; + const struct memcheck_stat *ls = l, *rs = r; return compare_values(rs->heap_size, ls->heap_size); } static int sort_by_alloc_time(const void *l, const void *r) { - const struct runstats *ls = l, *rs = r; + const struct memcheck_stat *ls = l, *rs = r; return compare_values(rs->alloc_max_ns, ls->alloc_max_ns); } static int sort_by_free_time(const void *l, const void *r) { - const struct runstats *ls = l, *rs = r; + const struct memcheck_stat *ls = l, *rs = r; return compare_values(rs->free_max_ns, ls->free_max_ns); } static int sort_by_frag(const void *l, const void *r) { - const struct runstats *ls = l, *rs = r; + const struct memcheck_stat *ls = l, *rs = r; - return compare_values(rs->fragmentation, ls->fragmentation); + return compare_values(rs->maximum_free - rs->largest_free, + ls->maximum_free - ls->largest_free); } static int sort_by_overhead(const void *l, const void *r) { - const struct runstats *ls = l, *rs = r; + const struct memcheck_stat *ls = l, *rs = r; - return compare_values(rs->overhead, ls->overhead); + return compare_values(rs->heap_size - rs->user_size, + ls->heap_size - ls->user_size); } static inline const char *get_debug_state(void) @@ -132,45 +153,12 @@ static inline const char *get_debug_state(void) #endif } -#ifdef CONFIG_XENO_COBALT - -#include <sys/cobalt.h> - -static inline void breathe(int loops) -{ - struct timespec idle = { - .tv_sec = 0, - .tv_nsec = 1000000, - }; - - /* - * There is not rt throttling over Cobalt, so we may need to - * keep the host kernel breathing by napping during the test - * sequences. - */ - if ((loops % 10000) == 0) - __RT(clock_nanosleep(CLOCK_MONOTONIC, 0, &idle, NULL)); -} - -static inline void harden(void) -{ - cobalt_thread_harden(); -} - -#else - -static inline void breathe(int loops) { } - -static inline void harden(void) { } - -#endif - static void __dump_stats(struct memcheck_descriptor *md, - struct runstats *stats, + struct memcheck_stat *stats, int (*sortfn)(const void *l, const void *r), int nr, const char *key) { - struct runstats *p; + struct memcheck_stat *p; int n; qsort(stats, nrstats, sizeof(*p), sortfn); @@ -190,11 +178,11 @@ static void __dump_stats(struct memcheck_descriptor *md, (double)p->free_avg_ns/1000.0, (double)p->alloc_max_ns/1000.0, (double)p->free_max_ns/1000.0, - p->overhead, - p->fragmentation, + 100.0 - (p->user_size * 100.0 / p->heap_size), + (1.0 - ((double)p->largest_free / p->maximum_free)) * 100.0, p->alloc_avg_ns == 0 && p->free_avg_ns == 0 ? "FAILED " : "", p->flags & MEMCHECK_SHUFFLE ? "+shuffle " : "", - p->flags & MEMCHECK_REALLOC ? "+realloc" : ""); + p->flags & MEMCHECK_HOT ? "+hot" : ""); } if (nr < nrstats) @@ -207,7 +195,7 @@ static int dump_stats(struct memcheck_descriptor *md, const char *title) double overhead_sum = 0.0, frag_sum = 0.0; long max_alloc_sum = 0, max_free_sum = 0; long avg_alloc_sum = 0, avg_free_sum = 0; - struct runstats *stats, *p, *next; + struct memcheck_stat *stats, *p, *next; int n; stats = __STD(malloc(sizeof(*p) * nrstats)); @@ -232,7 +220,7 @@ static int dump_stats(struct memcheck_descriptor *md, const char *title) smokey_trace("OVRH% overhead"); smokey_trace("FRAG% external fragmentation"); smokey_trace("FLAGS +shuffle: randomized free"); - smokey_trace(" +realloc: measure after initial alloc/free pass (hot heap)"); + smokey_trace(" +hot: measure after initial alloc/free pass (hot heap)"); if (max_results > 0) { if (max_results > nrstats) @@ -251,8 +239,8 @@ static int dump_stats(struct memcheck_descriptor *md, const char *title) max_free_sum += p->free_max_ns; avg_alloc_sum += p->alloc_avg_ns; avg_free_sum += p->free_avg_ns; - overhead_sum += p->overhead; - frag_sum += p->fragmentation; + overhead_sum += 100.0 - (p->user_size * 100.0 / p->heap_size); + frag_sum += (1.0 - ((double)p->largest_free / p->maximum_free)) * 100.0; if (p->alloc_max_ns > worst_alloc_max) worst_alloc_max = p->alloc_max_ns; if (p->free_max_ns > worst_free_max) @@ -357,33 +345,44 @@ static size_t find_largest_free(struct memcheck_descriptor *md, return free_size; } -static int test_seq(struct memcheck_descriptor *md, +/* + * The default test helper can exercise heap managers implemented in + * userland. + */ +static int default_test_seq(struct memcheck_descriptor *md, size_t heap_size, size_t block_size, int flags) { + size_t arena_size, user_size, largest_free, maximum_free, freed; long alloc_sum_ns, alloc_avg_ns, free_sum_ns, free_avg_ns, alloc_max_ns, free_max_ns, d; - size_t arena_size, user_size, largest_free, freed; int ret, n, k, maxblocks, nrblocks; struct timespec start, end; - struct runstats *stats; + struct memcheck_stat *st; + struct sched_param param; struct chunk *chunks; bool done_frag; void *mem, *p; - double frag; - arena_size = md->get_arena_size(heap_size); - if (arena_size == 0) { - smokey_trace("cannot get arena size for heap size %zu", - heap_size); - return -ENOMEM; + /* This switches to real-time mode over Cobalt. */ + param.sched_priority = 1; + pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m); + + arena_size = heap_size; + if (md->get_arena_size) { + arena_size = md->get_arena_size(heap_size); + if (arena_size == 0) { + smokey_trace("cannot get arena size for heap size %zu", + heap_size); + return -ENOMEM; + } } - maxblocks = heap_size / block_size; - mem = __STD(malloc(arena_size)); if (mem == NULL) return -ENOMEM; + maxblocks = heap_size / block_size; + ret = md->init(md->heap, mem, arena_size); if (ret) { smokey_trace("cannot init heap with arena size %zu", @@ -408,7 +407,8 @@ static int test_seq(struct memcheck_descriptor *md, free_avg_ns = 0; alloc_max_ns = 0; free_max_ns = 0; - frag = 0.0; + largest_free = 0; + maximum_free = 0; /* * With Cobalt, make sure to run in primary mode before the @@ -504,6 +504,7 @@ static int test_seq(struct memcheck_descriptor *md, k, chunks[k].pattern); goto bad; } + breathe(k); } } freed += block_size; @@ -518,7 +519,7 @@ static int test_seq(struct memcheck_descriptor *md, if (!done_frag && freed >= user_size / 2) { /* Calculate the external fragmentation. */ largest_free = find_largest_free(md, freed, block_size); - frag = (1.0 - ((double)largest_free / freed)) * 100.0; + maximum_free = freed; done_frag = true; } breathe(n); @@ -529,7 +530,7 @@ static int test_seq(struct memcheck_descriptor *md, * able to reproduce the same allocation pattern with the same * outcome, check this. */ - if (flags & MEMCHECK_REALLOC) { + if (flags & MEMCHECK_HOT) { for (n = 0, alloc_max_ns = alloc_sum_ns = 0; ; n++) { __RT(clock_gettime(CLOCK_MONOTONIC, &start)); p = md->alloc(md->heap, block_size); @@ -541,7 +542,7 @@ static int test_seq(struct memcheck_descriptor *md, if (p == NULL) break; if (n >= maxblocks) { - smokey_trace("too many blocks fetched during realloc" + smokey_trace("too many blocks fetched during hot pass" " (heap=%zu, block=%zu, " "got more than %d blocks)", heap_size, block_size, maxblocks); @@ -551,7 +552,7 @@ static int test_seq(struct memcheck_descriptor *md, breathe(n); } if (n != nrblocks) { - smokey_trace("inconsistent block count fetched during realloc" + smokey_trace("inconsistent block count fetched during hot pass" " (heap=%zu, block=%zu, " "got %d blocks vs %d during alloc)", heap_size, block_size, n, nrblocks); @@ -562,7 +563,7 @@ static int test_seq(struct memcheck_descriptor *md, ret = md->free(md->heap, chunks[n].ptr); __RT(clock_gettime(CLOCK_MONOTONIC, &end)); if (ret) { - smokey_trace("failed to free block %p during realloc" + smokey_trace("failed to free block %p during hot pass" "(heap=%zu, block=%zu)", chunks[n].ptr, heap_size, block_size); goto bad; @@ -597,26 +598,24 @@ do_stats: breathe(0); ret = 0; if (!(flags & MEMCHECK_PATTERN)) { - stats = __STD(malloc(sizeof(*stats))); - if (stats == NULL) { + st = __STD(malloc(sizeof(*st))); + if (st == NULL) { smokey_warning("failed allocating memory"); ret = -ENOMEM; goto oom; } - stats->heap_size = heap_size; - stats->user_size = user_size; - stats->block_size = block_size; - stats->nrblocks = nrblocks; - stats->alloc_avg_ns = alloc_avg_ns; - stats->alloc_max_ns = alloc_max_ns; - stats->free_avg_ns = free_avg_ns; - stats->free_max_ns = free_max_ns; - stats->overhead = 100.0 - (user_size * 100.0 / heap_size); - stats->fragmentation = frag; - stats->flags = flags; - stats->next = statistics; - statistics = stats; - nrstats++; + st->heap_size = heap_size; + st->user_size = user_size; + st->block_size = block_size; + st->nrblocks = nrblocks; + st->alloc_avg_ns = alloc_avg_ns; + st->alloc_max_ns = alloc_max_ns; + st->free_avg_ns = free_avg_ns; + st->free_max_ns = free_max_ns; + st->largest_free = largest_free; + st->maximum_free = maximum_free; + st->flags = flags; + memcheck_log_stat(st); } done: @@ -625,19 +624,22 @@ no_chunks: md->destroy(md->heap); out: if (ret) - smokey_trace("** '%s' FAILED(overhead %s, %sshuffle, %scheck, %srealloc): heapsz=%zuk, " + smokey_trace("** '%s' FAILED(overhead %s, %sshuffle, %scheck, %shot): heapsz=%zuk, " "blocksz=%zu, overhead=%zu (%.1f%%)", md->name, flags & MEMCHECK_ZEROOVRD ? "disallowed" : "allowed", flags & MEMCHECK_SHUFFLE ? "" : "no ", flags & MEMCHECK_PATTERN ? "" : "no ", - flags & MEMCHECK_REALLOC ? "" : "no ", + flags & MEMCHECK_HOT ? "" : "no ", heap_size / 1024, block_size, arena_size - heap_size, (arena_size * 100.0 / heap_size) - 100.0); oom: __STD(free(mem)); + param.sched_priority = 0; + pthread_setschedparam(pthread_self(), SCHED_OTHER, ¶m); + return ret; bad: ret = -EPROTO; @@ -649,13 +651,20 @@ static inline int test_flags(struct memcheck_descriptor *md, int flags) return md->valid_flags & flags; } +void memcheck_log_stat(struct memcheck_stat *st) +{ + st->next = statistics; + statistics = st; + nrstats++; +} + int memcheck_run(struct memcheck_descriptor *md, struct smokey_test *t, int argc, char *const argv[]) { - struct timespec idle = { .tv_sec = 0, .tv_nsec = 1000000 }; + int (*test_seq)(struct memcheck_descriptor *md, + size_t heap_size, size_t block_size, int flags); size_t heap_size, block_size; - struct sched_param param; cpu_set_t affinity; unsigned long seed; int ret, runs; @@ -683,11 +692,15 @@ int memcheck_run(struct memcheck_descriptor *md, if (smokey_arg_isset(t, "max_results")) max_results = smokey_arg_int(t, "max_results"); + test_seq = md->test_seq; + if (test_seq == NULL) + test_seq = default_test_seq; + now = time(NULL); seed = (unsigned long)now * getpid(); srandom(seed); - smokey_trace("== memcheck started at %s", ctime(&now)); + smokey_trace("== memcheck started for %s at %s", md->name, ctime(&now)); smokey_trace(" seq_heap_size=%zuk", md->seq_max_heap_size / 1024); smokey_trace(" random_alloc_rounds=%d", md->random_rounds); smokey_trace(" pattern_heap_size=%zuk", md->pattern_heap_size / 1024); @@ -701,10 +714,6 @@ int memcheck_run(struct memcheck_descriptor *md, return -ret; } - /* This switches to real-time mode over Cobalt. */ - param.sched_priority = 1; - pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m); - /* * Create a series of heaps of increasing size, allocating * then freeing all blocks sequentially from them, ^2 block @@ -720,7 +729,7 @@ int memcheck_run(struct memcheck_descriptor *md, for (block_size = 16; block_size < heap_size / 2; block_size <<= 1) { ret = test_seq(md, heap_size, block_size, - test_flags(md, MEMCHECK_ZEROOVRD)); + test_flags(md, MEMCHECK_ZEROOVRD)); if (ret) { smokey_trace("failed with %zuk heap, " "%zu-byte block (pow2)", @@ -731,10 +740,10 @@ int memcheck_run(struct memcheck_descriptor *md, for (block_size = 16; block_size < heap_size / 2; block_size <<= 1) { ret = test_seq(md, heap_size, block_size, - test_flags(md, MEMCHECK_ZEROOVRD|MEMCHECK_REALLOC)); + test_flags(md, MEMCHECK_ZEROOVRD|MEMCHECK_HOT)); if (ret) { smokey_trace("failed with %zuk heap, " - "%zu-byte block (pow2, realloc)", + "%zu-byte block (pow2, hot)", heap_size / 1024, block_size); return ret; } @@ -753,10 +762,10 @@ int memcheck_run(struct memcheck_descriptor *md, for (block_size = 16; block_size < heap_size / 2; block_size <<= 1) { ret = test_seq(md, heap_size, block_size, - test_flags(md, MEMCHECK_ZEROOVRD|MEMCHECK_REALLOC|MEMCHECK_SHUFFLE)); + test_flags(md, MEMCHECK_ZEROOVRD|MEMCHECK_HOT|MEMCHECK_SHUFFLE)); if (ret) { smokey_trace("failed with %zuk heap, " - "%zu-byte block (pow2, shuffle, realloc)", + "%zu-byte block (pow2, shuffle, hot)", heap_size / 1024, block_size); return ret; } @@ -792,10 +801,10 @@ int memcheck_run(struct memcheck_descriptor *md, for (runs = 0; runs < md->random_rounds; runs++) { block_size = (random() % (heap_size / 2)) ?: 1; ret = test_seq(md, heap_size, block_size, - test_flags(md, MEMCHECK_REALLOC)); + test_flags(md, MEMCHECK_HOT)); if (ret) { smokey_trace("failed with %zuk heap, " - "%zu-byte block (random, realloc)", + "%zu-byte block (random, hot)", heap_size / 1024, block_size); return ret; } @@ -822,10 +831,10 @@ int memcheck_run(struct memcheck_descriptor *md, for (runs = 0; runs < md->random_rounds; runs++) { block_size = (random() % (heap_size / 2)) ?: 1; ret = test_seq(md, heap_size, block_size, - test_flags(md, MEMCHECK_REALLOC|MEMCHECK_SHUFFLE)); + test_flags(md, MEMCHECK_HOT|MEMCHECK_SHUFFLE)); if (ret) { smokey_trace("failed with %zuk heap, " - "%zu-byte block (random, shuffle, realloc)", + "%zu-byte block (random, shuffle, hot)", heap_size / 1024, block_size); return ret; } @@ -840,12 +849,6 @@ int memcheck_run(struct memcheck_descriptor *md, " -- this may take some time)", md->name); for (runs = 0; runs < md->pattern_rounds; runs++) { - /* - * pattern check is CPU-consuming and tends to starve - * the host kernel from CPU for too long, relax a bit - * between loops. - */ - __RT(clock_nanosleep(CLOCK_MONOTONIC, 0, &idle, NULL)); block_size = (random() % (md->pattern_heap_size / 2)) ?: 1; ret = test_seq(md, md->pattern_heap_size, block_size, test_flags(md, MEMCHECK_SHUFFLE|MEMCHECK_PATTERN)); @@ -858,7 +861,8 @@ int memcheck_run(struct memcheck_descriptor *md, } now = time(NULL); - smokey_trace("\n== memcheck finished at %s", ctime(&now)); + smokey_trace("\n== memcheck finished for %s at %s", + md->name, ctime(&now)); return ret; } diff --git a/testsuite/smokey/memcheck/memcheck.h b/testsuite/smokey/memcheck/memcheck.h index 881d22d..b367726 100644 --- a/testsuite/smokey/memcheck/memcheck.h +++ b/testsuite/smokey/memcheck/memcheck.h @@ -10,12 +10,28 @@ #include <boilerplate/ancillaries.h> #include <smokey/smokey.h> +/* Must match RTTST_HEAPCHECK_* flags in uapi/testing.h */ #define MEMCHECK_ZEROOVRD 1 #define MEMCHECK_SHUFFLE 2 #define MEMCHECK_PATTERN 4 -#define MEMCHECK_REALLOC 8 +#define MEMCHECK_HOT 8 #define MEMCHECK_ALL_FLAGS 0xf +struct memcheck_stat { + size_t heap_size; + size_t user_size; + size_t block_size; + size_t maximum_free; + size_t largest_free; + int nrblocks; + long alloc_avg_ns; + long alloc_max_ns; + long free_avg_ns; + long free_max_ns; + int flags; + struct memcheck_stat *next; +}; + struct memcheck_descriptor { const char *name; int (*init)(void *heap, void *mem, size_t heap_size); @@ -32,6 +48,8 @@ struct memcheck_descriptor { int pattern_rounds; void *heap; int valid_flags; + int (*test_seq)(struct memcheck_descriptor *md, + size_t heap_size, size_t block_size, int flags); }; #define HEAP_INIT_T(__p) ((int (*)(void *heap, void *mem, size_t size))(__p)) @@ -58,6 +76,8 @@ struct memcheck_descriptor { "\tmax_results=<N>\t# of result lines (worst-case first, -1=all)\n" \ "\tSet --verbose=2 for detailed runtime statistics.\n" +void memcheck_log_stat(struct memcheck_stat *st); + int memcheck_run(struct memcheck_descriptor *md, struct smokey_test *t, int argc, char *const argv[]); diff --git a/testsuite/smokey/memory-coreheap/Makefile.am b/testsuite/smokey/memory-coreheap/Makefile.am new file mode 100644 index 0000000..d9a4466 --- /dev/null +++ b/testsuite/smokey/memory-coreheap/Makefile.am @@ -0,0 +1,9 @@ + +noinst_LIBRARIES = libmemory-coreheap.a + +libmemory_coreheap_a_SOURCES = coreheap.c + +libmemory_coreheap_a_CPPFLAGS = \ + @XENO_USER_CFLAGS@ \ + -I$(srcdir)/.. \ + -I$(top_srcdir)/include diff --git a/testsuite/smokey/memory-coreheap/coreheap.c b/testsuite/smokey/memory-coreheap/coreheap.c new file mode 100644 index 0000000..56e84ed --- /dev/null +++ b/testsuite/smokey/memory-coreheap/coreheap.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2018 Philippe Gerum <r...@xenomai.org> + * + * SPDX-License-Identifier: MIT + */ +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <pthread.h> +#include <rtdm/testing.h> +#include "memcheck/memcheck.h" + +smokey_test_plugin(memory_coreheap, + MEMCHECK_ARGS, + "Check for the Cobalt core allocator sanity.\n" + MEMCHECK_HELP_STRINGS + ); + +#define MIN_HEAP_SIZE 8192 +#define MAX_HEAP_SIZE (1024 * 1024 * 2) +#define RANDOM_ROUNDS 1024 + +#define PATTERN_HEAP_SIZE (128*1024) +#define PATTERN_ROUNDS 128 + +static int kernel_test_seq(struct memcheck_descriptor *md, + size_t heap_size, size_t block_size, int flags) +{ + struct rttst_heap_stathdr sthdr; + struct rttst_heap_parms parms; + struct rttst_heap_stats *p; + struct memcheck_stat *st; + struct sched_param param; + int fd, ret, n; + + fd = __RT(open("/dev/rtdm/heapcheck", O_RDWR)); + if (fd < 0) + return -ENOSYS; + + /* This switches to real-time mode over Cobalt. */ + param.sched_priority = 1; + pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m); + + parms.heap_size = heap_size; + parms.block_size = block_size; + parms.flags = flags; + ret = __RT(ioctl(fd, RTTST_RTIOC_HEAP_CHECK, &parms)); + if (ret) + goto out; + + if (parms.nrstats == 0) + goto out; + + sthdr.nrstats = parms.nrstats; + sthdr.buf = __STD(malloc(sizeof(*sthdr.buf) * parms.nrstats)); + if (sthdr.buf == NULL) { + ret = -ENOMEM; + goto out; + } + + ret = __RT(ioctl(fd, RTTST_RTIOC_HEAP_STAT_COLLECT, &sthdr)); + if (ret) + goto out; + + for (n = sthdr.nrstats, p = sthdr.buf; n > 0; n--, p++) { + st = __STD(malloc(sizeof(*st))); + if (st == NULL) { + ret = -ENOMEM; + goto out; + } + st->heap_size = p->heap_size; + st->user_size = p->user_size; + st->block_size = p->block_size; + st->nrblocks = p->nrblocks; + st->alloc_avg_ns = p->alloc_avg_ns; + st->alloc_max_ns = p->alloc_max_ns; + st->free_avg_ns = p->free_avg_ns; + st->free_max_ns = p->free_max_ns; + st->maximum_free = p->maximum_free; + st->largest_free = p->largest_free; + st->flags = p->flags; + memcheck_log_stat(st); + } +out: + __RT(close(fd)); + + param.sched_priority = 0; + pthread_setschedparam(pthread_self(), SCHED_OTHER, ¶m); + + return ret; +} + +static struct memcheck_descriptor coreheap_descriptor = { + .name = "coreheap", + .seq_min_heap_size = MIN_HEAP_SIZE, + .seq_max_heap_size = MAX_HEAP_SIZE, + .random_rounds = RANDOM_ROUNDS, + .pattern_heap_size = PATTERN_HEAP_SIZE, + .pattern_rounds = PATTERN_ROUNDS, + .valid_flags = MEMCHECK_ALL_FLAGS, + .test_seq = kernel_test_seq, +}; + +static int run_memory_coreheap(struct smokey_test *t, + int argc, char *const argv[]) +{ + return memcheck_run(&coreheap_descriptor, t, argc, argv); +} _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org https://xenomai.org/mailman/listinfo/xenomai-git