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

317 lines
8.9 KiB
C

/*
* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* Redistribution and use 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 be used 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/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/queue.h>
#include <linux/msm_ion.h>
#include "memory_prof.h"
#include "memory_prof_util.h"
#include "alloc_profiles.h"
static LIST_HEAD(simple_alloc_list, simple_alloc_node) simple_alloc_head;
struct simple_alloc_node {
char *alloc_id;
ion_user_handle_t handle;
struct simple_alloc_op *simple_alloc_op;
LIST_ENTRY(simple_alloc_node) nodes;
};
struct simple_alloc_op {
char alloc_id[MAX_ALLOC_ID_STRING_LEN];
unsigned int heap_id;
char heap_id_string[MAX_HEAP_ID_STRING_LEN];
unsigned int flags;
char flags_string[MAX_FLAGS_STRING_LEN];
unsigned long size;
char size_string[MAX_SIZE_STRING_LEN];
};
enum simple_alloc_op_line_idx {
SA_LINE_IDX_ALLOC_ID = 1,
SA_LINE_IDX_HEAP_ID,
SA_LINE_IDX_FLAGS,
SA_LINE_IDX_ALLOC_SIZE_BYTES,
SA_LINE_IDX_ALLOC_SIZE_LABEL,
};
int simple_ion_fd;
static int op_simple_alloc_global_setup(
struct alloc_profile_entry entries[] __unused)
{
LIST_INIT(&simple_alloc_head);
simple_ion_fd = open(ION_DEV, O_RDONLY);
if (simple_ion_fd < 0)
err(1, "couldn't open " ION_DEV);
return 0;
}
static void op_simple_alloc_global_teardown(void)
{
close(simple_ion_fd);
}
static int op_simple_alloc_parse(struct alloc_profile_entry *entry,
struct line_info *li)
{
unsigned int heap_id;
struct simple_alloc_op *op = (struct simple_alloc_op *) entry->priv;
char **words = li->words;
STRNCPY_SAFE(op->alloc_id, words[SA_LINE_IDX_ALLOC_ID],
MAX_ALLOC_ID_STRING_LEN);
if (find_heap_id_value(words[SA_LINE_IDX_HEAP_ID], &heap_id))
warn("Unknown heap_id: %s", words[SA_LINE_IDX_HEAP_ID]);
op->heap_id = ION_HEAP(heap_id);
STRNCPY_SAFE(op->heap_id_string, words[SA_LINE_IDX_HEAP_ID],
MAX_HEAP_ID_STRING_LEN);
op->flags = (unsigned int)parse_flags(words[SA_LINE_IDX_FLAGS]);
STRNCPY_SAFE(op->flags_string, words[SA_LINE_IDX_FLAGS],
MAX_FLAGS_STRING_LEN);
if (parse_size_string(words[SA_LINE_IDX_ALLOC_SIZE_BYTES],
&op->size)) {
warnx("Couldn't parse alloc_bytes %s into a size",
words[SA_LINE_IDX_ALLOC_SIZE_BYTES]);
return 1;
}
STRNCPY_SAFE(op->size_string, words[SA_LINE_IDX_ALLOC_SIZE_LABEL],
MAX_SIZE_STRING_LEN);
return 0;
}
static int op_simple_alloc_run(struct alloc_profile_entry *entry)
{
struct simple_alloc_node *np;
struct simple_alloc_op *op = (struct simple_alloc_op *) entry->priv;
struct ion_allocation_data alloc_data = {
.align = SZ_4K,
.len = op->size,
.heap_id_mask = op->heap_id,
.flags = op->flags,
};
MALLOC(struct simple_alloc_node *,
np, sizeof(struct simple_alloc_node));
if (alloc_me_up_some_ion(simple_ion_fd, &alloc_data)) {
warn("Couldn't do Ion alloc");
return 1;
}
np->handle = alloc_data.handle;
np->alloc_id = op->alloc_id;
np->simple_alloc_op = op;
LIST_INSERT_HEAD(&simple_alloc_head, np, nodes);
return 0;
}
static struct alloc_profile_ops simple_alloc_ops = {
.parse = op_simple_alloc_parse,
.run = op_simple_alloc_run,
.global_setup = op_simple_alloc_global_setup,
.global_teardown = op_simple_alloc_global_teardown,
};
ALLOC_PROFILE_OP_SIZED(&simple_alloc_ops, simple_alloc,
sizeof(struct simple_alloc_op));
struct simple_free_op {
char alloc_id[MAX_ALLOC_ID_STRING_LEN];
};
static int op_simple_free_parse(struct alloc_profile_entry *entry,
struct line_info *li)
{
struct simple_free_op *op = (struct simple_free_op *) entry->priv;
STRNCPY_SAFE(op->alloc_id, li->words[1], MAX_ALLOC_ID_STRING_LEN);
return 0;
}
static int op_simple_free_run(struct alloc_profile_entry *entry)
{
struct simple_free_op *op = (struct simple_free_op *) entry->priv;
struct simple_alloc_node *np;
for (np = simple_alloc_head.lh_first;
np != NULL;
np = np->nodes.le_next) {
struct ion_handle_data data;
if (strcmp(np->alloc_id, op->alloc_id))
continue;
data.handle = np->handle;
if (ioctl(simple_ion_fd, ION_IOC_FREE, &data))
err(1, "Couldn't do ION_IOC_FREE");
LIST_REMOVE(np, nodes);
free(np);
}
return 0;
}
static struct alloc_profile_ops simple_free_ops = {
.parse = op_simple_free_parse,
.run = op_simple_free_run,
};
ALLOC_PROFILE_OP_SIZED(&simple_free_ops, simple_free,
sizeof(struct simple_free_op));
struct simple_profile_op {
char alloc_id[MAX_ALLOC_ID_STRING_LEN];
};
static int op_simple_profile_parse(struct alloc_profile_entry *entry,
struct line_info *li)
{
struct simple_profile_op *op = (struct simple_profile_op *) entry->priv;
STRNCPY_SAFE(op->alloc_id, li->words[1], MAX_ALLOC_ID_STRING_LEN);
return 0;
}
static struct simple_alloc_node *find_by_alloc_id(char *alloc_id)
{
struct simple_alloc_node *np;
/* find the parameters that were used for allocation */
for (np = simple_alloc_head.lh_first;
np != NULL;
np = np->nodes.le_next) {
if (!strcmp(np->alloc_id, alloc_id))
return np;
}
return NULL;
}
static int op_simple_profile_run(struct alloc_profile_entry *entry)
{
int i, ret;
double map_ms, memset_ms;
unsigned long size;
ion_user_handle_t handle;
char sbuf[70], *heap_id_string = NULL, *flags_string, *size_string;
struct simple_profile_op *op = (struct simple_profile_op *) entry->priv;
struct simple_alloc_node *np;
heap_id_string = flags_string = size_string = NULL;
/* find the parameters that were used for allocation */
np = find_by_alloc_id(op->alloc_id);
if (!np) {
warnx("Couldn't find a simple allocation with id %s. Bailing.",
op->alloc_id);
return 1;
}
heap_id_string = np->simple_alloc_op->heap_id_string;
flags_string = np->simple_alloc_op->flags_string;
size_string = np->simple_alloc_op->size_string;
size = np->simple_alloc_op->size;
handle = np->handle;
ret = do_profile_alloc_for_heap(
0, 0, size, NULL, &map_ms, &memset_ms, NULL,
false, handle, simple_ion_fd, false);
if (ret) {
warn("Couldn't profile %s. Bailing.",
op->alloc_id);
return 1;
}
snprintf(sbuf, 70, "mmap %s", heap_id_string);
print_stats_results(sbuf, flags_string, size_string, &map_ms, 1);
snprintf(sbuf, 70, "memset %s", heap_id_string);
print_stats_results(sbuf, flags_string, size_string, &memset_ms, 1);
putchar('\n');
fflush(stdout);
return 0;
}
static struct alloc_profile_ops simple_profile_ops = {
.parse = op_simple_profile_parse,
.run = op_simple_profile_run,
};
ALLOC_PROFILE_OP_SIZED(&simple_profile_ops, simple_profile,
sizeof(struct simple_profile_op));
struct simple_basic_sanity_op {
char alloc_id[MAX_ALLOC_ID_STRING_LEN];
};
static int op_simple_basic_sanity_parse(struct alloc_profile_entry *entry,
struct line_info *li)
{
struct simple_basic_sanity_op *op =
(struct simple_basic_sanity_op *) entry->priv;
STRNCPY_SAFE(op->alloc_id, li->words[1], MAX_ALLOC_ID_STRING_LEN);
return 0;
}
static int op_simple_basic_sanity_run(struct alloc_profile_entry *entry)
{
struct simple_basic_sanity_op *op =
(struct simple_basic_sanity_op *) entry->priv;
struct simple_alloc_node *np;
np = find_by_alloc_id(op->alloc_id);
if (!np) {
warnx("Couldn't find a simple allocation with id %s. Bailing.",
op->alloc_id);
return 1;
}
if (do_basic_ion_sanity_test(simple_ion_fd, np->handle,
np->simple_alloc_op->size)) {
warnx("Basic sanity test on %s failed!", op->alloc_id);
return 1;
}
return 0;
}
static struct alloc_profile_ops simple_basic_sanity_ops = {
.parse = op_simple_basic_sanity_parse,
.run = op_simple_basic_sanity_run,
};
ALLOC_PROFILE_OP_SIZED(&simple_basic_sanity_ops, simple_basic_sanity,
sizeof(struct simple_basic_sanity_op));