/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2019 MediaTek Inc. */ #define TMEM_PROFILE_FMT #define PR_FMT_HEADER_MUST_BE_INCLUDED_BEFORE_ALL_HDRS #include "private/tmem_pr_fmt.h" PR_FMT_HEADER_MUST_BE_INCLUDED_BEFORE_ALL_HDRS #include #include #include #include #include #include #include #include #include #include #include "private/mld_helper.h" #include "private/tmem_error.h" #include "private/tmem_device.h" #include "private/tmem_utils.h" #include "private/tmem_priv.h" struct profile_entry_string { int idx; const char *str; }; #define STR(a) #a struct profile_entry_string profile_entry_str[] = { {PROFILE_ENTRY_SSMR_GET, STR(SSMR_GET)}, {PROFILE_ENTRY_SSMR_PUT, STR(SSMR_PUT)}, {PROFILE_ENTRY_CHUNK_ALLOC, STR(CHUNK_ALLOC)}, {PROFILE_ENTRY_CHUNK_FREE, STR(CHUNK_FREE)}, {PROFILE_ENTRY_MEM_ADD, STR(MEM_ADD)}, {PROFILE_ENTRY_MEM_REMOVE, STR(MEM_REMOVE)}, {PROFILE_ENTRY_SESSION_OPEN, STR(SESSION_OPEN)}, {PROFILE_ENTRY_SESSION_CLOSE, STR(SESSION_CLOSE)}, {PROFILE_ENTRY_INVOKE_COMMAND, STR(INVOKE_COMMAND)}, }; #define GET_START_TIME() do_gettimeofday(&start_time) #define GET_END_TIME() do_gettimeofday(&end_time) #define SEC_TO_US(s) (s*1000000) #include static inline u64 u64_div(u64 n, u64 base) { do_div(n, base); return n; } static inline u64 us_to_ms(u64 us) { return u64_div(us, 1000); } static bool is_valid_profile_entry(enum PROFILE_ENTRY_TYPE entry) { return ((entry >= PROFILE_ENTRY_SSMR_GET) && (entry < PROFILE_ENTRY_MAX)); } void trusted_mem_core_profile_dump(struct trusted_mem_device *mem_device) { int idx; u64 average_one_time_us; u64 average_one_time_ms; struct profile_data_context *data = &mem_device->profile_mgr->data; pr_info("=================================================\n"); pr_info("[%d] Profiling Summary:\n", mem_device->mem_type); for (idx = 0; idx < PROFILE_ENTRY_MAX; idx++) { average_one_time_us = SEC_TO_US(data->item[idx].sec); average_one_time_us += data->item[idx].usec; average_one_time_us = u64_div(average_one_time_us, data->item[idx].count); average_one_time_ms = us_to_ms(average_one_time_us); pr_info("[%d] Entry: %s\n", mem_device->mem_type, profile_entry_str[idx].str); pr_info("[%d] invoke count: %lld\n", mem_device->mem_type, data->item[idx].count); pr_info("[%d] spend time: %lld.%06lld sec\n", mem_device->mem_type, data->item[idx].sec, data->item[idx].usec); pr_info("[%d] average one time: %lld msec (%06lld usec)\n", mem_device->mem_type, average_one_time_ms, average_one_time_us); } pr_info("=================================================\n"); } static void increase_enter_count(enum PROFILE_ENTRY_TYPE entry, struct profile_data_context *data) { if (!is_valid_profile_entry(entry)) return; mutex_lock(&data->item[entry].lock); data->item[entry].count++; mutex_unlock(&data->item[entry].lock); } static void add_exec_time(enum PROFILE_ENTRY_TYPE entry, struct profile_data_context *data, struct timeval *start, struct timeval *end) { int time_diff_sec = GET_TIME_DIFF_SEC_P(start, end); int time_diff_usec = GET_TIME_DIFF_USEC_P(start, end); if (!is_valid_profile_entry(entry)) return; mutex_lock(&data->item[entry].lock); data->item[entry].sec += time_diff_sec; data->item[entry].usec += time_diff_usec; if (data->item[entry].usec > 1000000) { data->item[entry].sec += 1; data->item[entry].usec -= 1000000; } mutex_unlock(&data->item[entry].lock); } static int profile_ssmr_get(u64 *pa, u32 *size, u32 feat, void *dev_desc) { int ret; struct timeval start_time, end_time; struct profile_mgr_desc *prof_mgr = (struct profile_mgr_desc *)dev_desc; increase_enter_count(PROFILE_ENTRY_SSMR_GET, &prof_mgr->data); GET_START_TIME(); ret = prof_mgr->profiled_ssmr_ops->offline(pa, size, feat, prof_mgr->profiled_dev_desc); GET_END_TIME(); add_exec_time(PROFILE_ENTRY_SSMR_GET, &prof_mgr->data, &start_time, &end_time); return ret; } static int profile_ssmr_put(u32 feat, void *dev_desc) { int ret; struct timeval start_time, end_time; struct profile_mgr_desc *prof_mgr = (struct profile_mgr_desc *)dev_desc; increase_enter_count(PROFILE_ENTRY_SSMR_PUT, &prof_mgr->data); GET_START_TIME(); ret = prof_mgr->profiled_ssmr_ops->online(feat, prof_mgr->profiled_dev_desc); GET_END_TIME(); add_exec_time(PROFILE_ENTRY_SSMR_PUT, &prof_mgr->data, &start_time, &end_time); return ret; } static int profile_chunk_alloc(u32 alignment, u32 size, u32 *refcount, u32 *sec_handle, u8 *owner, u32 id, u32 clean, void *peer_data, void *dev_desc) { int ret; struct timeval start_time, end_time; struct profile_mgr_desc *prof_mgr = (struct profile_mgr_desc *)dev_desc; increase_enter_count(PROFILE_ENTRY_CHUNK_ALLOC, &prof_mgr->data); GET_START_TIME(); ret = prof_mgr->profiled_peer_ops->memory_alloc( alignment, size, refcount, sec_handle, owner, id, clean, peer_data, prof_mgr->profiled_dev_desc); GET_END_TIME(); add_exec_time(PROFILE_ENTRY_CHUNK_ALLOC, &prof_mgr->data, &start_time, &end_time); return ret; } static int profile_chunk_free(u32 sec_handle, u8 *owner, u32 id, void *peer_data, void *dev_desc) { int ret; struct timeval start_time, end_time; struct profile_mgr_desc *prof_mgr = (struct profile_mgr_desc *)dev_desc; increase_enter_count(PROFILE_ENTRY_CHUNK_FREE, &prof_mgr->data); GET_START_TIME(); ret = prof_mgr->profiled_peer_ops->memory_free( sec_handle, owner, id, peer_data, prof_mgr->profiled_dev_desc); GET_END_TIME(); add_exec_time(PROFILE_ENTRY_CHUNK_FREE, &prof_mgr->data, &start_time, &end_time); return ret; } static int profile_mem_add(u64 pa, u32 size, void *peer_data, void *dev_desc) { int ret; struct timeval start_time, end_time; struct profile_mgr_desc *prof_mgr = (struct profile_mgr_desc *)dev_desc; increase_enter_count(PROFILE_ENTRY_MEM_ADD, &prof_mgr->data); GET_START_TIME(); ret = prof_mgr->profiled_peer_ops->memory_grant( pa, size, peer_data, prof_mgr->profiled_dev_desc); GET_END_TIME(); add_exec_time(PROFILE_ENTRY_MEM_ADD, &prof_mgr->data, &start_time, &end_time); return ret; } static int profile_mem_remove(void *peer_data, void *dev_desc) { int ret; struct timeval start_time, end_time; struct profile_mgr_desc *prof_mgr = (struct profile_mgr_desc *)dev_desc; increase_enter_count(PROFILE_ENTRY_MEM_REMOVE, &prof_mgr->data); GET_START_TIME(); ret = prof_mgr->profiled_peer_ops->memory_reclaim( peer_data, prof_mgr->profiled_dev_desc); GET_END_TIME(); add_exec_time(PROFILE_ENTRY_MEM_REMOVE, &prof_mgr->data, &start_time, &end_time); return ret; } static int profile_session_open(void **peer_data, void *dev_desc) { int ret; struct timeval start_time, end_time; struct profile_mgr_desc *prof_mgr = (struct profile_mgr_desc *)dev_desc; increase_enter_count(PROFILE_ENTRY_SESSION_OPEN, &prof_mgr->data); GET_START_TIME(); ret = prof_mgr->profiled_peer_ops->session_open( peer_data, prof_mgr->profiled_dev_desc); GET_END_TIME(); add_exec_time(PROFILE_ENTRY_SESSION_OPEN, &prof_mgr->data, &start_time, &end_time); return ret; } static int profile_session_close(void *peer_data, void *dev_desc) { int ret; struct timeval start_time, end_time; struct profile_mgr_desc *prof_mgr = (struct profile_mgr_desc *)dev_desc; increase_enter_count(PROFILE_ENTRY_SESSION_CLOSE, &prof_mgr->data); GET_START_TIME(); ret = prof_mgr->profiled_peer_ops->session_close( peer_data, prof_mgr->profiled_dev_desc); GET_END_TIME(); add_exec_time(PROFILE_ENTRY_SESSION_CLOSE, &prof_mgr->data, &start_time, &end_time); return ret; } static int profile_invoke_command(struct trusted_driver_cmd_params *invoke_params, void *peer_data, void *dev_desc) { int ret; struct timeval start_time, end_time; struct profile_mgr_desc *prof_mgr = (struct profile_mgr_desc *)dev_desc; increase_enter_count(PROFILE_ENTRY_INVOKE_COMMAND, &prof_mgr->data); GET_START_TIME(); ret = prof_mgr->profiled_peer_ops->invoke_cmd( invoke_params, peer_data, prof_mgr->profiled_dev_desc); GET_END_TIME(); add_exec_time(PROFILE_ENTRY_INVOKE_COMMAND, &prof_mgr->data, &start_time, &end_time); return ret; } static struct trusted_driver_operations profiler_peer_ops = { .session_open = profile_session_open, .session_close = profile_session_close, .memory_alloc = profile_chunk_alloc, .memory_free = profile_chunk_free, .memory_grant = profile_mem_add, .memory_reclaim = profile_mem_remove, .invoke_cmd = profile_invoke_command, }; static struct ssmr_operations profiler_ssmr_ops = { .offline = profile_ssmr_get, .online = profile_ssmr_put, }; struct profile_mgr_desc *create_profile_mgr_desc(void) { int idx; struct profile_mgr_desc *t_profile_desc; pr_info("TMEM_PROFILE_ENABLED\n"); t_profile_desc = mld_kmalloc(sizeof(struct profile_mgr_desc), GFP_KERNEL); if (INVALID(t_profile_desc)) { pr_err("%s:%d out of memory!\n", __func__, __LINE__); return NULL; } for (idx = 0; idx < PROFILE_ENTRY_MAX; idx++) { mutex_init(&t_profile_desc->data.item[idx].lock); t_profile_desc->data.item[idx].count = 0; t_profile_desc->data.item[idx].sec = 0; t_profile_desc->data.item[idx].usec = 0; } t_profile_desc->profiled_peer_ops = &profiler_peer_ops; t_profile_desc->profiled_ssmr_ops = &profiler_ssmr_ops; t_profile_desc->profiled_dev_desc = t_profile_desc; return t_profile_desc; }