/* * 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 #include #include #include #include #include #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));