M7350/qcom-opensource/kernel/kernel-tests/memory_prof/op-user-alloc.c
2024-09-09 08:57:42 +00:00

237 lines
6.3 KiB
C

/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* Redistribution ande in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may beed to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <unistd.h>
#include <sys/mman.h>
#include "memory_prof.h"
#include "memory_prof_util.h"
#include "alloc_profiles.h"
enum user_allocator {
ALLOCATOR_MALLOC,
ALLOCATOR_MMAP,
};
enum usage_fn {
USAGE_FN_NOP,
USAGE_FN_MEMSET_N,
};
struct user_alloc_op {
enum user_allocator user_allocator;
enum usage_fn usage_fn;
unsigned int memset_n_arg; /* only for USAGE_FN_MEMSET_N */
unsigned long alloc_bytes;
unsigned long usage_bytes;
char user_allocator_string[MAX_ALLOC_PROFILE_WORD_LEN];
char usage_fn_string[MAX_ALLOC_PROFILE_WORD_LEN];
char alloc_bytes_string[MAX_ALLOC_PROFILE_WORD_LEN];
char usage_bytes_string[MAX_ALLOC_PROFILE_WORD_LEN];
};
#define LINE_IDX_ALLOCATOR 1
#define LINE_IDX_ALLOC_BYTES 2
#define LINE_IDX_USAGE_BYTES 3
#define LINE_IDX_USAGE_FN 4
static int op_user_alloc_parse(struct alloc_profile_entry *entry,
struct line_info *li)
{
struct user_alloc_op *op = (struct user_alloc_op *) entry->priv;
char **words = li->words;
char *cur;
cur = words[LINE_IDX_ALLOCATOR];
if (!strcmp("malloc", cur)) {
op->user_allocator = ALLOCATOR_MALLOC;
} else if (!strcmp("mmap", cur)) {
op->user_allocator = ALLOCATOR_MMAP;
} else {
warnx("Unknown allocator: %s", cur);
return 1;
}
STRNCPY_SAFE(op->user_allocator_string, cur,
MAX_ALLOC_PROFILE_WORD_LEN);
cur = words[LINE_IDX_ALLOC_BYTES];
if (parse_size_string(cur, &op->alloc_bytes)) {
warnx("Couldn't parse alloc_bytes %s into a size",
cur);
return 1;
}
STRNCPY_SAFE(op->alloc_bytes_string, cur, MAX_ALLOC_PROFILE_WORD_LEN);
cur = words[LINE_IDX_USAGE_BYTES];
if (parse_size_string(cur, &op->usage_bytes)) {
warnx("Couldn't parse usage_bytes %s into a size", cur);
return 1;
}
STRNCPY_SAFE(op->usage_bytes_string, cur, MAX_ALLOC_PROFILE_WORD_LEN);
cur = words[LINE_IDX_USAGE_FN];
if (!strcmp("nop", cur)) {
op->usage_fn = USAGE_FN_NOP;
} else if (!strncmp("memset-", cur, strlen("memset-"))) {
op->usage_fn = USAGE_FN_MEMSET_N;
STRTOL(op->memset_n_arg, cur + strlen("memset-"), 0);
} else {
warnx("Unknown usage_fn: %s\n", cur);
return 1;
}
STRNCPY_SAFE(op->usage_fn_string, cur, MAX_ALLOC_PROFILE_WORD_LEN);
return 0;
}
static void *do_mmap_alloc(size_t len)
{
void *buf = mmap(NULL, len,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
if (buf == MAP_FAILED) {
warn("Couldn't allocate buffer with mmap\n");
return NULL;
}
return buf;
}
static void do_munmap(void *buf, size_t len)
{
munmap(buf, len);
}
static void do_free(void *buf, size_t len __unused)
{
free(buf);
}
static int memset_n_arg;
static void do_memset_n(void *buf, size_t len)
{
memset(buf, memset_n_arg, len);
}
static void identity(void *buf __unused, size_t len __unused)
{
}
static int op_user_alloc_run(struct alloc_profile_entry *entry)
{
int rc, rc2, i;
struct timeval tv_before, tv_after;
void *buf;
struct user_alloc_op *op = (struct user_alloc_op *) entry->priv;
double alloc_timing, usage_timing, free_timing;
void *(*alloc_fn)(size_t len);
void (*free_fn)(void *, size_t);
void (*usage_fn)(void *, size_t) = NULL;
struct munmapper *unmapper;
switch (op->user_allocator) {
case ALLOCATOR_MALLOC:
alloc_fn = malloc;
free_fn = do_free;
break;
case ALLOCATOR_MMAP:
alloc_fn = do_mmap_alloc;
free_fn = do_munmap;
break;
default:
errx(1, "Backwards cheeseburgers found. Calling it a day.");
return 1;
}
switch (op->usage_fn) {
case USAGE_FN_NOP:
usage_fn = identity;
break;
case USAGE_FN_MEMSET_N:
usage_fn = do_memset_n;
memset_n_arg = op->memset_n_arg;
break;
default:
errx(1, "usage_fn cheeseburg'd. Calling it a day.");
return 1;
}
rc = gettimeofday(&tv_before, NULL);
buf = alloc_fn(op->alloc_bytes);
rc2 = gettimeofday(&tv_after, NULL);
if (!buf) {
warn("Couldn't allocate memory!");
return 1;
}
if (rc || rc2) {
warn("Couldn't get time of day!");
free(buf);
return 1;
}
alloc_timing = timeval_ms_diff(tv_after, tv_before);
rc = gettimeofday(&tv_before, NULL);
usage_fn(buf, op->usage_bytes);
rc2 = gettimeofday(&tv_after, NULL);
if (rc || rc2) {
warn("Couldn't get time of day!");
return 1;
}
usage_timing = timeval_ms_diff(tv_after, tv_before);
rc = gettimeofday(&tv_before, NULL);
free_fn(buf, op->alloc_bytes);
rc2 = gettimeofday(&tv_after, NULL);
if (rc || rc2) {
warn("Couldn't get time of day!");
return 1;
}
free_timing = timeval_ms_diff(tv_after, tv_before);
printf(ST_PREFIX_DATA_ROW
" user_alloc %s: %g %s: %g alloc_size: %s usage_size: %s free: %g\n",
op->user_allocator_string, alloc_timing,
op->usage_fn_string, usage_timing,
op->alloc_bytes_string,
op->usage_bytes_string,
free_timing);
return 0;
}
static struct alloc_profile_ops user_alloc_ops = {
.parse = op_user_alloc_parse,
.run = op_user_alloc_run,
};
ALLOC_PROFILE_OP_SIZED(&user_alloc_ops, user_alloc,
sizeof(struct user_alloc_op));