ARM: mali400: r5p2_rel0: add GLES mem profiler feature 56/69356/2
authorYoungJun Cho <yj44.cho@samsung.com>
Tue, 21 Jul 2015 04:19:27 +0000 (13:19 +0900)
committerJoonyoung Shim <jy0922.shim@samsung.com>
Mon, 23 May 2016 06:41:30 +0000 (15:41 +0900)
This patch adds GLES mem profiler feature.

You could use it by "cat /sys/kernel/debug/mali/gles_mem/<PID>".
Without user-DDK's MALI_IOC_MEM_PROFILE_GLES_MEM, it only show layout.

With this ioctl, you could check current GLES relevant memory status
in opened session and also check memory leakage in trash subdirectory.

The mechanism of detecting memory leakage is checking information when
the session is closed. So the user misses to free (GLES)memory during
session, it(the PID) could be found in trash.

Caution! When app is killed and the session is forcely shut down, then
it(the PID) could be found in trash but we can not guarantee there is a
real memory leakage. That is because like this case, it is impossible
to call MALI_IOC_MEM_PROFILE_GLES_MEM to remove allocated memory.

Change-Id: I78a08f7b53594dc20f8cc6f4c892250fdc9e8208
Signed-off-by: YoungJun Cho <yj44.cho@samsung.com>
[jy0922.shim: applied to r5p2_rel0 from r5p0_rel0]
Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
drivers/gpu/arm/mali400/r5p2_rel0/Kbuild
drivers/gpu/arm/mali400/r5p2_rel0/common/mali_session.c
drivers/gpu/arm/mali400/r5p2_rel0/common/mali_session.h
drivers/gpu/arm/mali400/r5p2_rel0/include/linux/mali/mali_utgard_ioctl.h
drivers/gpu/arm/mali400/r5p2_rel0/include/linux/mali/mali_utgard_uk_types.h
drivers/gpu/arm/mali400/r5p2_rel0/linux/mali_kernel_linux.c
drivers/gpu/arm/mali400/r5p2_rel0/linux/mali_kernel_sysfs.c
drivers/gpu/arm/mali400/r5p2_rel0/linux/mali_kernel_sysfs.h
drivers/gpu/arm/mali400/r5p2_rel0/linux/mali_ukk_mem.c
drivers/gpu/arm/mali400/r5p2_rel0/linux/mali_ukk_wrappers.h

index 9605fd3..8bd7891 100644 (file)
@@ -25,6 +25,7 @@ MALI_PLATFORM ?= sc8830
 MALI_FAKE_PLATFORM_DEVICE ?= 1
 DFS_ONE_STEP_SCALE_DOWN ?= 1
 MATCH_DFS_TO_LOWER_FREQ ?= 1
+GLES_MEM_PROFILE ?= 1
 
 # The GPL product will only include the license/gpl directory
 ccflags-y += -I$(src)/linux/license/gpl
@@ -134,6 +135,7 @@ ccflags-y += $(EXTRA_DEFINES)
 ccflags-y += -DSPRD_GPU_BOOST
 ccflags-y += -DSPRD_DFS_ONE_STEP_SCALE_DOWN=$(DFS_ONE_STEP_SCALE_DOWN)
 ccflags-y += -DSPRD_MATCH_DFS_TO_LOWER_FREQ=$(MATCH_DFS_TO_LOWER_FREQ)
+ccflags-y += -DTIZEN_GLES_MEM_PROFILE=$(GLES_MEM_PROFILE)
 
 ccflags-y += -DMALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP=$(MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP)
 ccflags-y += -DMALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED=$(MALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED)
index 8f31e35..fd8827b 100644 (file)
@@ -12,6 +12,9 @@
 #include "mali_osk_list.h"
 #include "mali_session.h"
 #include "mali_ukk.h"
+#if TIZEN_GLES_MEM_PROFILE
+#include "mali_kernel_sysfs.h"
+#endif
 
 _MALI_OSK_LIST_HEAD(mali_sessions);
 static u32 mali_session_count = 0;
@@ -40,16 +43,86 @@ void mali_session_terminate(void)
        }
 }
 
+#if TIZEN_GLES_MEM_PROFILE
+static void mali_session_gles_mem_init(struct mali_session_data *session)
+{
+       struct mali_session_gles_mem_profile_info *info;
+       int i;
+
+       mali_sysfs_gles_mem_profile_add((void *)session);
+
+       for (i = 0; i < MALI_MAX_GLES_MEM_TYPES; i++) {
+               info = &(session->gles_mem_profile_info[i]);
+               info->type = i;
+               info->lock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,
+                                               _MALI_OSK_LOCK_ORDER_SESSIONS);
+               if (!info->lock)
+                       MALI_PRINT_ERROR(("Mutex init failure"));
+               _MALI_OSK_INIT_LIST_HEAD(&(info->api_head));
+       }
+}
+
+static void mali_session_gles_mem_profile_apis_remove(
+                               struct mali_session_gles_mem_profile_info *info)
+{
+       struct mali_session_gles_mem_profile_api_info *api, *tmp;
+
+       _mali_osk_mutex_wait(info->lock);
+
+       _MALI_OSK_LIST_FOREACHENTRY(api, tmp, &(info->api_head),
+                       struct mali_session_gles_mem_profile_api_info, link) {
+               _mali_osk_list_delinit(&(api->link));
+               _mali_osk_free(api);
+       }
+
+       _mali_osk_mutex_signal(info->lock);
+}
+
+static void mali_session_gles_mem_deinit(struct mali_session_data *session)
+{
+       struct mali_session_gles_mem_profile_trash_info *trash_info = NULL;
+       struct mali_session_gles_mem_profile_info *info;
+       int i;
+
+       for (i = 0; i < MALI_MAX_GLES_MEM_TYPES; i++) {
+               info = &(session->gles_mem_profile_info[i]);
+               if (!info->lock)
+                       continue;
+
+               if (info->size) {
+                       trash_info =
+                       (struct mali_session_gles_mem_profile_trash_info *)
+                               mali_sysfs_gles_mem_profile_move_to_trash(
+                                                       (void *)trash_info,
+                                                       (void *)session, i);
+               } else
+                       mali_session_gles_mem_profile_apis_remove(info);
+
+               _mali_osk_mutex_term(info->lock);
+       }
+
+       mali_sysfs_gles_mem_profile_remove((void *)session);
+}
+#endif /* TIZEN_GLES_MEM_PROFILE */
+
 void mali_session_add(struct mali_session_data *session)
 {
        mali_session_lock();
        _mali_osk_list_add(&session->link, &mali_sessions);
        mali_session_count++;
        mali_session_unlock();
+
+#if TIZEN_GLES_MEM_PROFILE
+       mali_session_gles_mem_init(session);
+#endif
 }
 
 void mali_session_remove(struct mali_session_data *session)
 {
+#if TIZEN_GLES_MEM_PROFILE
+       mali_session_gles_mem_deinit(session);
+#endif
+
        mali_session_lock();
        _mali_osk_list_delinit(&session->link);
        mali_session_count--;
@@ -111,3 +184,121 @@ void mali_session_memory_tracking(_mali_osk_print_ctx *print_ctx)
        total_mali_mem_size = _mali_ukk_report_total_memory_size();
        _mali_osk_ctxprintf(print_ctx, "Mali mem usage: %u\nMali mem limit: %u\n", mali_mem_usage, total_mali_mem_size);
 }
+
+#if TIZEN_GLES_MEM_PROFILE
+void mali_session_gles_mem_profile_api_add(
+                       struct mali_session_gles_mem_profile_info *info,
+                       struct mali_session_gles_mem_profile_api_info *api,
+                       _mali_osk_list_t *head)
+{
+       if (!info->lock)
+               return;
+
+       _mali_osk_mutex_wait(info->lock);
+
+       _mali_osk_list_add(&(api->link), head);
+
+       _mali_osk_mutex_signal(info->lock);
+}
+
+static const char *mali_session_gles_mem_profile_to_str(
+                               enum mali_session_gles_mem_profile_type type)
+{
+       switch (type) {
+       case MALI_GLES_MEM_UNTYPED:
+               return "mali_gles_mem Untyped";
+       case MALI_GLES_MEM_VB_IB:
+               return "mali_gles_mem Vertex & Index buffer";
+       case MALI_GLES_MEM_TEXTURE:
+               return "mali_gles_mem Texture";
+       case MALI_GLES_MEM_RSW:
+               return "mali_gles_mem RSW";
+       case MALI_GLES_MEM_PLBU_HEAP:
+               return "mali_gles_mem PLBU heap";
+       case MALI_GLES_MEM_UNTYPE_GP_CMD_LIST:
+               return "mali_gles_mem Uuntyped GP cmd list";
+       case MALI_GLES_MEM_SHADER:
+               return "mali_gles_mem Shader";
+       case MALI_GLES_MEM_TD:
+               return "mali_gles_mem TD";
+       case MALI_GLES_MEM_UNTYPE_FRAME_POOL:
+               return "mali_gles_mem Untyped frame pool";
+       case MALI_GLES_MEM_UNTYPE_SURFACE:
+               return "mali_gles_mem Untyped surface";
+       case MALI_GLES_MEM_RT:
+               return "mali_gles_mem Render target";
+       case MALI_GLES_MEM_VARYING:
+               return "mali_gles_mem Varying buffer";
+       case MALI_GLES_MEM_STREAMS:
+               return "mali_gles_mem Streams buffer";
+       case MALI_GLES_MEM_POINTER_ARRAY:
+               return "mali_gles_mem Pointer array buffer";
+       case MALI_GLES_MEM_SLAVE_TILE_LIST:
+               return "mali_gles_mem Slave tile list buffer";
+       case MALI_GLES_MEM_POLYGON_CMD_LIST:
+               return "mali_gles_mem Polygon cmd list";
+       case MALI_GLES_MEM_FRAGMENT_STACK:
+               return "mali_gles_mem Fragment stack";
+       case MALI_GLES_MEM_UNIFORM:
+               return "mali_gles_mem Uniforms";
+       case MALI_GLES_MEM_PBUFFER:
+               return "mali_gles_mem Pbuffer";
+       default:
+               return "mali_gles_mem Untyped";
+       }
+}
+
+static void mali_session_gles_mem_profile_api_tracking(
+                               _mali_osk_print_ctx *print_ctx,
+                               struct mali_session_gles_mem_profile_info *info)
+{
+       struct mali_session_gles_mem_profile_api_info *api, *tmp;
+
+       _MALI_OSK_LIST_FOREACHENTRY(api, tmp, &(info->api_head),
+                       struct mali_session_gles_mem_profile_api_info, link) {
+               _mali_osk_ctxprintf(print_ctx, "\t| %-36s\t%-30d\n",
+                                       api->api, api->size);
+       }
+}
+
+s64 mali_session_gles_mem_profile_info_tracking(_mali_osk_print_ctx *print_ctx,
+                                                       void *data, bool trash)
+{
+       struct mali_session_gles_mem_profile_trash_info *trash_info = NULL;
+       struct mali_session_gles_mem_profile_info *info;
+       struct mali_session_data *session = NULL;
+       s64 total_size = 0;
+       int i;
+
+       MALI_DEBUG_ASSERT_POINTER(print_ctx);
+       MALI_DEBUG_ASSERT_POINTER(data);
+
+       if (trash) {
+               trash_info =
+                       (struct mali_session_gles_mem_profile_trash_info *)data;
+       } else
+               session = (struct mali_session_data *)data;
+
+       for (i = 0; i < MALI_MAX_GLES_MEM_TYPES; i++) {
+               if (trash)
+                       info = &(trash_info->info[i]);
+               else
+                       info = &(session->gles_mem_profile_info[i]);
+               if (!info->lock)
+                       continue;
+
+               _mali_osk_mutex_wait(info->lock);
+
+               _mali_osk_ctxprintf(print_ctx, "%-36s\t%-30lld\n",
+                                       mali_session_gles_mem_profile_to_str(
+                                               i << MALI_GLES_MEM_SHIFT),
+                                       info->size);
+               mali_session_gles_mem_profile_api_tracking(print_ctx, info);
+               total_size += info->size;
+
+               _mali_osk_mutex_signal(info->lock);
+       }
+
+       return total_size;
+}
+#endif /* TIZEN_GLES_MEM_PROFILE */
index 02256cf..9158be4 100644 (file)
@@ -23,6 +23,67 @@ struct mali_soft_system;
 /* Number of frame builder job lists per session. */
 #define MALI_PP_JOB_FB_LOOKUP_LIST_SIZE 16
 #define MALI_PP_JOB_FB_LOOKUP_LIST_MASK (MALI_PP_JOB_FB_LOOKUP_LIST_SIZE - 1)
+#if TIZEN_GLES_MEM_PROFILE
+#define MALI_GLES_MEM_SHIFT    8
+
+enum mali_session_gles_mem_profile_type {
+       MALI_GLES_MEM_PP_READ                   = (1 << 0),
+       MALI_GLES_MEM_PP_WRITE                  = (1 << 1),
+       MALI_GLES_MEM_GP_READ                   = (1 << 2),
+       MALI_GLES_MEM_GP_WRITE                  = (1 << 3),
+       MALI_GLES_MEM_CPU_READ                  = (1 << 4),
+       MALI_GLES_MEM_CPU_WRITE                 = (1 << 5),
+       MALI_GLES_MEM_GP_L2_ALLOC               = (1 << 6),
+       MALI_GLES_MEM_FRAME_POOL_ALLOC          = (1 << 7),
+       /* type of this mem block */
+       MALI_GLES_MEM_UNTYPED                   = (0 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_VB_IB                     = (1 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_TEXTURE                   = (2 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_VARYING                   = (3 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_RT                        = (4 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_PBUFFER                   = (5 << MALI_GLES_MEM_SHIFT),
+       /* memory types for gp command */
+       MALI_GLES_MEM_PLBU_HEAP                 = (6 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_POINTER_ARRAY             = (7 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_SLAVE_TILE_LIST           = (8 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_UNTYPE_GP_CMD_LIST        = (9 << MALI_GLES_MEM_SHIFT),
+       /* memory type for polygon list command */
+       MALI_GLES_MEM_POLYGON_CMD_LIST          = (10 << MALI_GLES_MEM_SHIFT),
+       /* memory types for pp command */
+       MALI_GLES_MEM_TD                        = (11 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_RSW                       = (12 << MALI_GLES_MEM_SHIFT),
+       /* other memory types */
+       MALI_GLES_MEM_SHADER                    = (13 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_STREAMS                   = (14 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_FRAGMENT_STACK            = (15 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_UNIFORM                   = (16 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_UNTYPE_FRAME_POOL         = (17 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_UNTYPE_SURFACE            = (18 << MALI_GLES_MEM_SHIFT),
+       MALI_GLES_MEM_MAX                       = (19 << MALI_GLES_MEM_SHIFT),
+};
+
+#define MALI_MAX_GLES_MEM_TYPES        (MALI_GLES_MEM_MAX >> MALI_GLES_MEM_SHIFT)
+
+struct mali_session_gles_mem_profile_api_info {
+       char api[64]; /**< API name */
+       u16 id; /**< API ID */
+       int size; /**< Total size for this API */
+       _MALI_OSK_LIST_HEAD(link); /**< Link for the list of all EGL/GL API */
+};
+
+struct mali_session_gles_mem_profile_info {
+       u32 type; /**< Memory type ID */
+       s64 size; /**< Total sizes for this type */
+       _mali_osk_mutex_t *lock; /**< Mutex lock */
+       _mali_osk_list_t api_head; /**< List of all EGL/GL APIs for this type */
+};
+
+struct mali_session_gles_mem_profile_trash_info {
+       u32 pid;
+       char *comm;
+       struct mali_session_gles_mem_profile_info info[MALI_MAX_GLES_MEM_TYPES];
+};
+#endif /* TIZEN_GLES_MEM_PROFILE */
 
 struct mali_session_data {
        _mali_osk_notification_queue_t *ioctl_queue;
@@ -57,6 +118,12 @@ struct mali_session_data {
 #ifdef SPRD_GPU_BOOST
        int level;
 #endif
+
+#if TIZEN_GLES_MEM_PROFILE
+       struct dentry *gles_mem_profile_dentry;
+       struct mali_session_gles_mem_profile_info
+                               gles_mem_profile_info[MALI_MAX_GLES_MEM_TYPES];
+#endif
 };
 
 _mali_osk_errcode_t mali_session_initialize(void);
@@ -124,4 +191,13 @@ u32 mali_session_max_window_num(void);
 
 void mali_session_memory_tracking(_mali_osk_print_ctx *print_ctx);
 
+#if TIZEN_GLES_MEM_PROFILE
+void mali_session_gles_mem_profile_api_add(
+                       struct mali_session_gles_mem_profile_info *info,
+                       struct mali_session_gles_mem_profile_api_info *api,
+                       _mali_osk_list_t *head);
+s64 mali_session_gles_mem_profile_info_tracking(_mali_osk_print_ctx *print_ctx,
+                                                       void *data, bool trash);
+#endif
+
 #endif /* __MALI_SESSION_H__ */
index 72585f4..e0e2c4f 100644 (file)
@@ -62,6 +62,9 @@ extern "C" {
 #define MALI_IOC_MEM_QUERY_MMU_PAGE_TABLE_DUMP_SIZE _IOR (MALI_IOC_MEMORY_BASE, _MALI_UK_QUERY_MMU_PAGE_TABLE_DUMP_SIZE, _mali_uk_query_mmu_page_table_dump_size_s)
 #define MALI_IOC_MEM_DUMP_MMU_PAGE_TABLE    _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_DUMP_MMU_PAGE_TABLE, _mali_uk_dump_mmu_page_table_s)
 #define MALI_IOC_MEM_WRITE_SAFE             _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_MEM_WRITE_SAFE, _mali_uk_mem_write_safe_s)
+#if TIZEN_GLES_MEM_PROFILE
+#define MALI_IOC_MEM_PROFILE_GLES_MEM       _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_GLES_MEM_PROFILER, _mali_uk_gles_mem_profiler_s)
+#endif
 
 #define MALI_IOC_PP_START_JOB               _IOWR(MALI_IOC_PP_BASE, _MALI_UK_PP_START_JOB, _mali_uk_pp_start_job_s)
 #define MALI_IOC_PP_AND_GP_START_JOB        _IOWR(MALI_IOC_PP_BASE, _MALI_UK_PP_AND_GP_START_JOB, _mali_uk_pp_and_gp_start_job_s)
index 4344b2f..fd6e51a 100644 (file)
@@ -95,6 +95,9 @@ typedef enum {
        _MALI_UK_DUMP_MMU_PAGE_TABLE,            /**< _mali_ukk_mem_dump_mmu_page_table() */
        _MALI_UK_DMA_BUF_GET_SIZE,               /**< _mali_ukk_dma_buf_get_size() */
        _MALI_UK_MEM_WRITE_SAFE,                 /**< _mali_uku_mem_write_safe() */
+#if TIZEN_GLES_MEM_PROFILE
+       _MALI_UK_GLES_MEM_PROFILER,              /**< _mali_uku_gles_mem_profiler() */
+#endif
 
        /** Common functions for each core */
 
@@ -840,6 +843,19 @@ typedef struct {
        u64 page_table_dump;           /**< [out] pointer within buffer where MMU page table dump is stored */
 } _mali_uk_dump_mmu_page_table_s;
 
+#if TIZEN_GLES_MEM_PROFILE
+/**
+ * @brief Arguments for _mali_uk[uk]_gles_mem_profiler()
+ */
+typedef struct {
+       u64 ctx;        /**< [in,out] user-kernel context (trashed on output) */
+       char api[64];   /**< [in] OpenGLES or EGL API function name */
+       u32  entrypoint;/**< [in] OpenGLES or EGL API entrypoint */
+       u32  type;      /**< [in] Type of memory */
+       int  size;      /**< [in] Number of bytes. +ve means allocated. -ve means freed */
+} _mali_uk_gles_mem_profiler_s;
+#endif
+
 /** @} */ /* end group _mali_uk_memory */
 
 
index e1fe5f3..2493266 100644 (file)
@@ -883,6 +883,15 @@ static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 #endif
                break;
 
+#if TIZEN_GLES_MEM_PROFILE
+       case MALI_IOC_MEM_PROFILE_GLES_MEM:
+               BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_gles_mem_profiler_s),
+                               sizeof(u64)));
+               err = mem_profile_gles_mem(session_data,
+                               (_mali_uk_gles_mem_profiler_s __user *)arg);
+               break;
+#endif
+
        case MALI_IOC_PP_START_JOB:
                BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_pp_start_job_s), sizeof(u64)));
                err = pp_start_job_wrapper(session_data, (_mali_uk_pp_start_job_s __user *)arg);
index ea334c9..34e0084 100644 (file)
 #define POWER_BUFFER_SIZE 3
 
 static struct dentry *mali_debugfs_dir = NULL;
+#if TIZEN_GLES_MEM_PROFILE
+struct dentry *mali_gles_mem_profile_dir;
+struct dentry *mali_gles_mem_profile_trash_dir;
+#endif
 
 typedef enum {
        _MALI_DEVICE_SUSPEND,
@@ -1357,6 +1361,12 @@ int mali_sysfs_register(const char *mali_dev_name)
 #endif
                        }
 
+#if TIZEN_GLES_MEM_PROFILE
+                       mali_gles_mem_profile_dir = debugfs_create_dir(
+                                                       "gles_mem",
+                                                       mali_debugfs_dir);
+#endif
+
 #if MALI_STATE_TRACKING
                        debugfs_create_file("state_dump", 0400, mali_debugfs_dir, NULL, &mali_seq_internal_state_fops);
 #endif
@@ -1383,6 +1393,172 @@ int mali_sysfs_unregister(void)
        return 0;
 }
 
+#if TIZEN_GLES_MEM_PROFILE
+static void gles_mem_profile_show_common(struct seq_file *s, char *comm,
+                                                                       u32 pid)
+{
+       seq_printf(s,
+               "%s\n"
+               "%s (%s)\t\t%s(%d)\n"
+               "%s\n%s\t\t\t\t%s(%s)\n"
+               "\t| %s\t\t\t\t%s(%s)\n%s\n",
+       "===============================================================",
+       "Process name", comm, "Process ID", pid,
+       "---------------------------------------------------------------",
+       "Type Name", "Type Usage", "bytes", "API Name", "API Usage", "bytes",
+       "***************************************************************");
+}
+
+static int gles_mem_profile_show(struct seq_file *s, void *private_data)
+{
+       struct mali_session_data *session =
+                               (struct mali_session_data *)(s->private);
+
+       gles_mem_profile_show_common(s, session->comm, session->pid);
+
+       seq_printf(s, "\n\nTotal Mali GLES mem usage: %lld (bytes)\n",
+               mali_session_gles_mem_profile_info_tracking(s,
+                                                       (void *)session,
+                                                       false));
+
+       return 0;
+}
+
+static int gles_mem_profile_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, gles_mem_profile_show, inode->i_private);
+}
+
+static const struct file_operations gles_mem_profile_fops = {
+       .owner = THIS_MODULE,
+       .open = gles_mem_profile_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release
+};
+
+int mali_sysfs_gles_mem_profile_add(void *data)
+{
+       struct mali_session_data *session = (struct mali_session_data *)data;
+       char name[11];
+
+       if (!mali_gles_mem_profile_dir)
+               return 0;
+
+       _mali_osk_snprintf(name, sizeof(name), "%u", session->pid);
+       session->gles_mem_profile_dentry =
+                       debugfs_create_file(name, S_IRUSR,
+                                               mali_gles_mem_profile_dir,
+                                               (void *)session,
+                                               &gles_mem_profile_fops);
+
+       return 0;
+}
+
+void mali_sysfs_gles_mem_profile_remove(void *data)
+{
+       struct mali_session_data *session = (struct mali_session_data *)data;
+
+       debugfs_remove(session->gles_mem_profile_dentry);
+}
+
+static int gles_mem_profile_trash_show(struct seq_file *s, void *private_data)
+{
+       struct mali_session_gles_mem_profile_trash_info *trash_info =
+               (struct mali_session_gles_mem_profile_trash_info *)(s->private);
+
+       gles_mem_profile_show_common(s, trash_info->comm, trash_info->pid);
+
+       seq_printf(s, "\n\nTotal Mali GLES mem usage: %lld (bytes)\n",
+               mali_session_gles_mem_profile_info_tracking(s,
+                                                       (void *)trash_info,
+                                                       true));
+
+       return 0;
+}
+
+static int gles_mem_profile_trash_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, gles_mem_profile_trash_show, inode->i_private);
+}
+
+static const struct file_operations gles_mem_profile_trash_fops = {
+       .owner = THIS_MODULE,
+       .open = gles_mem_profile_trash_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release
+};
+
+void *mali_sysfs_gles_mem_profile_move_to_trash(void *data1, void *data2,
+                                                                       int idx)
+{
+       struct mali_session_gles_mem_profile_trash_info *trash_info =
+               (struct mali_session_gles_mem_profile_trash_info *)data1;
+       struct mali_session_data *session = (struct mali_session_data *)data2;
+       struct mali_session_gles_mem_profile_info *tinfo, *info;
+
+       if (!mali_gles_mem_profile_dir)
+               return NULL;
+
+       if (!trash_info) {
+               char name[11];
+               int i;
+
+               trash_info =
+                       (struct mali_session_gles_mem_profile_trash_info *)
+                       _mali_osk_calloc(1,
+                       sizeof(struct mali_session_gles_mem_profile_trash_info)
+                       );
+               if (!trash_info) {
+                       MALI_PRINT_ERROR(("TrashInfo alloc failure"));
+                       return NULL;
+               }
+
+               trash_info->pid = session->pid;
+               trash_info->comm = session->comm;
+
+               for (i = 0; i < MALI_MAX_GLES_MEM_TYPES; i++) {
+                       tinfo = &(trash_info->info[i]);
+                       tinfo->type = i;
+                       tinfo->lock =
+                               _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,
+                                               _MALI_OSK_LOCK_ORDER_SESSIONS);
+                       if (!tinfo->lock)
+                               MALI_PRINT_ERROR(("Mutex init failure"));
+                       _MALI_OSK_INIT_LIST_HEAD(&(tinfo->api_head));
+               }
+
+               if (!mali_gles_mem_profile_trash_dir) {
+                       mali_gles_mem_profile_trash_dir =
+                               debugfs_create_dir("trash",
+                                               mali_gles_mem_profile_dir);
+               }
+
+               _mali_osk_snprintf(name, sizeof(name), "%u", trash_info->pid);
+               debugfs_create_file(name, S_IRUSR,
+                                               mali_gles_mem_profile_trash_dir,
+                                               (void *)trash_info,
+                                               &gles_mem_profile_trash_fops);
+       }
+
+       tinfo = &(trash_info->info[idx]);
+       info = &(session->gles_mem_profile_info[idx]);
+
+       _mali_osk_mutex_wait(info->lock);
+
+       if (tinfo->lock) {
+               tinfo->type = info->type;
+               tinfo->size = info->size;
+               _mali_osk_list_move_list(&(info->api_head), &(tinfo->api_head));
+       }
+
+       _mali_osk_mutex_signal(info->lock);
+
+       return trash_info;
+}
+#endif /* TIZEN_GLES_MEM_PROFILE */
+
 #else /* MALI_LICENSE_IS_GPL */
 
 /* Dummy implementations for non-GPL */
@@ -1397,4 +1573,21 @@ int mali_sysfs_unregister(void)
        return 0;
 }
 
+#if TIZEN_GLES_MEM_PROFILE
+int mali_sysfs_gles_mem_profile_add(void *data)
+{
+       return 0;
+}
+
+void mali_sysfs_gles_mem_profile_remove(void *data)
+{
+       return;
+}
+
+void *mali_sysfs_gles_mem_profile_move_to_trash(void *data1, void *data2,
+                                                                       int idx)
+{
+       return NULL;
+}
+#endif /* TIZEN_GLES_MEM_PROFILE */
 #endif /* MALI_LICENSE_IS_GPL */
index a36a0ce..7fcc04f 100644 (file)
@@ -21,6 +21,12 @@ extern "C" {
 
 int mali_sysfs_register(const char *mali_dev_name);
 int mali_sysfs_unregister(void);
+#if TIZEN_GLES_MEM_PROFILE
+int mali_sysfs_gles_mem_profile_add(void *data);
+void mali_sysfs_gles_mem_profile_remove(void *data);
+void *mali_sysfs_gles_mem_profile_move_to_trash(void *data1, void *data2,
+                                                               int idx);
+#endif
 
 #ifdef __cplusplus
 }
index 96a0d42..c03ac8a 100644 (file)
@@ -308,3 +308,62 @@ int mem_usage_get_wrapper(struct mali_session_data *session_data, _mali_uk_profi
        return 0;
 }
 
+#if TIZEN_GLES_MEM_PROFILE
+int mem_profile_gles_mem(struct mali_session_data *session_data,
+                               _mali_uk_gles_mem_profiler_s __user *uargs)
+{
+       _mali_uk_gles_mem_profiler_s kargs;
+       struct mali_session_gles_mem_profile_info *info;
+       struct mali_session_gles_mem_profile_api_info *api, *tmp;
+       mali_bool flag = MALI_FALSE;
+
+       MALI_CHECK_NON_NULL(uargs, -EINVAL);
+       MALI_CHECK_NON_NULL(session_data, -EINVAL);
+
+       if (copy_from_user(&kargs, uargs, sizeof(_mali_uk_gles_mem_profiler_s)))
+               return -EFAULT;
+
+       kargs.ctx = (uintptr_t)session_data;
+
+       info = &session_data->gles_mem_profile_info[kargs.type];
+       if (!info) {
+               MALI_PRINT_ERROR(("No info is available. Something wrong"));
+               return -EINVAL;
+       }
+
+       _MALI_OSK_LIST_FOREACHENTRY(api, tmp, &(info->api_head),
+                       struct mali_session_gles_mem_profile_api_info, link) {
+               if (api->id == (u16)kargs.entrypoint) {
+                       /* This API is recorded already. Update it. */
+                       api->size += kargs.size;
+                       info->size += kargs.size;
+                       flag = MALI_TRUE;
+                       break;
+               }
+       }
+
+       if (flag == MALI_FALSE) {
+               /*
+                * This is the first time the API is recorded for this info.
+                * So add it.
+                */
+               api = (struct mali_session_gles_mem_profile_api_info *)
+                       _mali_osk_calloc(1,
+                       sizeof(struct mali_session_gles_mem_profile_api_info));
+               if (!api) {
+                       MALI_PRINT_ERROR(("Alloc failure"));
+                       return -ENOMEM;
+               }
+               memcpy(&api->api, &kargs.api, sizeof(api->api));
+
+               api->id = (u16)kargs.entrypoint;
+               api->size += kargs.size;
+               info->size += kargs.size;
+
+               mali_session_gles_mem_profile_api_add(info, api,
+                                                       &(info->api_head));
+       }
+
+       return 0;
+}
+#endif
index 9eef135..4e80c3d 100644 (file)
@@ -40,6 +40,10 @@ int mem_write_safe_wrapper(struct mali_session_data *session_data, _mali_uk_mem_
 int mem_query_mmu_page_table_dump_size_wrapper(struct mali_session_data *session_data, _mali_uk_query_mmu_page_table_dump_size_s __user *uargs);
 int mem_dump_mmu_page_table_wrapper(struct mali_session_data *session_data, _mali_uk_dump_mmu_page_table_s __user *uargs);
 int mem_usage_get_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_memory_usage_get_s __user *uargs);
+#if TIZEN_GLES_MEM_PROFILE
+int mem_profile_gles_mem(struct mali_session_data *session_data,
+                               _mali_uk_gles_mem_profiler_s __user *uargs);
+#endif
 
 int timeline_get_latest_point_wrapper(struct mali_session_data *session, _mali_uk_timeline_get_latest_point_s __user *uargs);
 int timeline_wait_wrapper(struct mali_session_data *session, _mali_uk_timeline_wait_s __user *uargs);