| /*************************************************************************/ /*! |
| @File |
| @Title Process based statistics |
| @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved |
| @Description Manages a collection of statistics based around a process |
| and referenced via OS agnostic methods. |
| @License Dual MIT/GPLv2 |
| |
| The contents of this file are subject to the MIT license as set out below. |
| |
| Permission is hereby granted, free of charge, to any person obtaining a copy |
| of this software and associated documentation files (the "Software"), to deal |
| in the Software without restriction, including without limitation the rights |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the Software is |
| furnished to do so, subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be included in |
| all copies or substantial portions of the Software. |
| |
| Alternatively, the contents of this file may be used under the terms of |
| the GNU General Public License Version 2 ("GPL") in which case the provisions |
| of GPL are applicable instead of those above. |
| |
| If you wish to allow use of your version of this file only under the terms of |
| GPL, and not to allow others to use your version of this file under the terms |
| of the MIT license, indicate your decision by deleting the provisions above |
| and replace them with the notice and other provisions required by GPL as set |
| out in the file called "GPL-COPYING" included in this distribution. If you do |
| not delete the provisions above, a recipient may use your version of this file |
| under the terms of either the MIT license or GPL. |
| |
| This License is also included in this distribution in the file called |
| "MIT-COPYING". |
| |
| EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS |
| PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING |
| BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
| PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR |
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ /**************************************************************************/ |
| |
| #include "img_defs.h" |
| #include "img_types.h" |
| #include "pvr_debug.h" |
| #include "lock.h" |
| #include "allocmem.h" |
| #include "osfunc.h" |
| #include "lists.h" |
| #include "process_stats.h" |
| #include "ri_server.h" |
| #include "hash.h" |
| #include "connection_server.h" |
| #include "pvrsrv.h" |
| #include "proc_stats.h" |
| #include "htbuffer.h" |
| #include "pvr_ricommon.h" |
| |
| /* Enabled OS Statistics entries: DEBUGFS on Linux, undefined for other OSs */ |
| #if defined(LINUX) && ( \ |
| defined(PVRSRV_ENABLE_PERPID_STATS) || \ |
| defined(PVRSRV_ENABLE_CACHEOP_STATS) || \ |
| defined(PVRSRV_ENABLE_MEMORY_STATS) || \ |
| defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) ) |
| #define ENABLE_DEBUGFS_PIDS |
| #endif |
| |
| /* |
| * Maximum history of process statistics that will be kept. |
| */ |
| #define MAX_DEAD_LIST_PROCESSES (10) |
| |
| /* |
| * Definition of all the strings used to format process based statistics. |
| */ |
| |
| #if defined(PVRSRV_ENABLE_PERPID_STATS) |
| /* Array of Process stat type defined using the X-Macro */ |
| #define X(stat_type, stat_str) stat_str, |
| const IMG_CHAR *const pszProcessStatType[PVRSRV_PROCESS_STAT_TYPE_COUNT] = { PVRSRV_PROCESS_STAT_KEY }; |
| #undef X |
| #endif |
| |
| /* Array of Driver stat type defined using the X-Macro */ |
| #define X(stat_type, stat_str) stat_str, |
| const IMG_CHAR *const pszDriverStatType[PVRSRV_DRIVER_STAT_TYPE_COUNT] = { PVRSRV_DRIVER_STAT_KEY }; |
| #undef X |
| |
| /* structure used in hash table to track statistic entries */ |
| typedef struct{ |
| size_t uiSizeInBytes; |
| IMG_PID uiPid; |
| }_PVR_STATS_TRACKING_HASH_ENTRY; |
| |
| /* Function used internally to decrement tracked per-process statistic entries */ |
| static void _StatsDecrMemTrackedStat(_PVR_STATS_TRACKING_HASH_ENTRY *psTrackingHashEntry, |
| PVRSRV_MEM_ALLOC_TYPE eAllocType); |
| |
| #if defined(PVRSRV_ENABLE_MEMTRACK_STATS_FILE) |
| void RawProcessStatsPrintElements(void *pvFile, |
| void *pvStatPtr, |
| OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf); |
| #endif |
| |
| void PowerStatsPrintElements(void *pvFile, |
| void *pvStatPtr, |
| OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf); |
| |
| void GlobalStatsPrintElements(void *pvFile, |
| void *pvStatPtr, |
| OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf); |
| |
| /* Note: all of the accesses to the global stats should be protected |
| * by the gsGlobalStats.hGlobalStatsLock lock. This means all of the |
| * invocations of macros *_GLOBAL_STAT_VALUE. */ |
| |
| /* Macro for fetching stat values */ |
| #define GET_GLOBAL_STAT_VALUE(idx) gsGlobalStats.ui32StatValue[idx] |
| /* |
| * Macros for updating stat values. |
| */ |
| #define UPDATE_MAX_VALUE(a,b) do { if ((b) > (a)) {(a) = (b);} } while(0) |
| #define INCREASE_STAT_VALUE(ptr,var,val) do { (ptr)->i32StatValue[(var)] += (val); if ((ptr)->i32StatValue[(var)] > (ptr)->i32StatValue[(var##_MAX)]) {(ptr)->i32StatValue[(var##_MAX)] = (ptr)->i32StatValue[(var)];} } while(0) |
| #define INCREASE_GLOBAL_STAT_VALUE(var,idx,val) do { (var).ui32StatValue[(idx)] += (val); if ((var).ui32StatValue[(idx)] > (var).ui32StatValue[(idx##_MAX)]) {(var).ui32StatValue[(idx##_MAX)] = (var).ui32StatValue[(idx)];} } while(0) |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| /* Allow stats to go negative */ |
| #define DECREASE_STAT_VALUE(ptr,var,val) do { (ptr)->i32StatValue[(var)] -= (val); } while(0) |
| #define DECREASE_GLOBAL_STAT_VALUE(var,idx,val) do { (var).ui32StatValue[(idx)] -= (val); } while(0) |
| #else |
| #define DECREASE_STAT_VALUE(ptr,var,val) do { if ((ptr)->i32StatValue[(var)] >= (val)) { (ptr)->i32StatValue[(var)] -= (val); } else { (ptr)->i32StatValue[(var)] = 0; } } while(0) |
| #define DECREASE_GLOBAL_STAT_VALUE(var,idx,val) do { if ((var).ui32StatValue[(idx)] >= (val)) { (var).ui32StatValue[(idx)] -= (val); } else { (var).ui32StatValue[(idx)] = 0; } } while(0) |
| #endif |
| #define MAX_CACHEOP_STAT 16 |
| #define INCREMENT_CACHEOP_STAT_IDX_WRAP(x) ((x+1) >= MAX_CACHEOP_STAT ? 0 : (x+1)) |
| #define DECREMENT_CACHEOP_STAT_IDX_WRAP(x) ((x-1) < 0 ? (MAX_CACHEOP_STAT-1) : (x-1)) |
| |
| /* |
| * Structures for holding statistics... |
| */ |
| |
| #if defined(PVRSRV_ENABLE_MEMORY_STATS) |
| typedef struct _PVRSRV_MEM_ALLOC_REC_ |
| { |
| PVRSRV_MEM_ALLOC_TYPE eAllocType; |
| IMG_UINT64 ui64Key; |
| void* pvCpuVAddr; |
| IMG_CPU_PHYADDR sCpuPAddr; |
| size_t uiBytes; |
| void* pvPrivateData; |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) && defined(DEBUG) |
| void* pvAllocdFromFile; |
| IMG_UINT32 ui32AllocdFromLine; |
| #endif |
| IMG_PID pid; |
| struct _PVRSRV_MEM_ALLOC_REC_* psNext; |
| struct _PVRSRV_MEM_ALLOC_REC_** ppsThis; |
| } PVRSRV_MEM_ALLOC_REC; |
| #endif |
| |
| typedef struct _PVRSRV_PROCESS_STATS_ { |
| |
| /* Linked list pointers */ |
| struct _PVRSRV_PROCESS_STATS_* psNext; |
| struct _PVRSRV_PROCESS_STATS_* psPrev; |
| |
| /* Create per process lock that need to be held |
| * to edit of its members */ |
| POS_LOCK hLock; |
| |
| /* OS level process ID */ |
| IMG_PID pid; |
| IMG_UINT32 ui32RefCount; |
| |
| /* Stats... */ |
| IMG_INT32 i32StatValue[PVRSRV_PROCESS_STAT_TYPE_COUNT]; |
| IMG_UINT32 ui32StatAllocFlags; |
| |
| #if defined(PVRSRV_ENABLE_CACHEOP_STATS) |
| struct _CACHEOP_STRUCT_ { |
| PVRSRV_CACHE_OP uiCacheOp; |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) && defined(DEBUG) |
| IMG_DEV_VIRTADDR sDevVAddr; |
| IMG_DEV_PHYADDR sDevPAddr; |
| RGXFWIF_DM eFenceOpType; |
| #endif |
| IMG_DEVMEM_SIZE_T uiOffset; |
| IMG_DEVMEM_SIZE_T uiSize; |
| IMG_UINT64 ui64ExecuteTime; |
| IMG_BOOL bRangeBasedFlush; |
| IMG_BOOL bUserModeFlush; |
| IMG_UINT32 ui32OpSeqNum; |
| IMG_BOOL bIsFence; |
| IMG_PID ownerPid; |
| } asCacheOp[MAX_CACHEOP_STAT]; |
| IMG_INT32 uiCacheOpWriteIndex; |
| #endif |
| |
| /* Other statistics structures */ |
| #if defined(PVRSRV_ENABLE_MEMORY_STATS) |
| PVRSRV_MEM_ALLOC_REC* psMemoryRecords; |
| #endif |
| } PVRSRV_PROCESS_STATS; |
| |
| #if defined (ENABLE_DEBUGFS_PIDS) |
| |
| typedef struct _PVRSRV_OS_STAT_ENTRY_ |
| { |
| void *pvOSStatsFolderData; |
| void *pvOSProcessStatsEntryData; |
| void *pvOSMemStatsEntryData; |
| void *pvOSRIMemStatsEntryData; |
| void *pvOSCacheOpStatsEntryData; |
| |
| } PVRSRV_OS_STAT_ENTRY; |
| |
| static PVRSRV_OS_STAT_ENTRY gsLiveStatEntries; |
| static PVRSRV_OS_STAT_ENTRY gsRetiredStatEntries; |
| |
| void GenericStatsPrintElementsLive(void *pvFile, |
| void *pvStatPtr, |
| OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf); |
| |
| void GenericStatsPrintElementsRetired(void *pvFile, |
| void *pvStatPtr, |
| OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf); |
| |
| /* |
| * Functions for printing the information stored... |
| */ |
| #if defined(PVRSRV_ENABLE_PERPID_STATS) |
| void ProcessStatsPrintElements(void *pvFile, |
| PVRSRV_PROCESS_STATS *psProcessStats, |
| OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf); |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_MEMORY_STATS) |
| void MemStatsPrintElements(void *pvFile, |
| PVRSRV_PROCESS_STATS *psProcessStats, |
| OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf); |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) |
| void RIMemStatsPrintElements(void *pvFile, |
| PVRSRV_PROCESS_STATS *psProcessStats, |
| OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf); |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_CACHEOP_STATS) |
| void CacheOpStatsPrintElements(void *pvFile, |
| PVRSRV_PROCESS_STATS *psProcessStats, |
| OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf); |
| #endif |
| |
| typedef void (PVRSRV_STATS_PRINT_ELEMENTS)(void *pvFile, |
| PVRSRV_PROCESS_STATS *psProcessStats, |
| OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf); |
| |
| typedef enum |
| { |
| PVRSRV_STAT_TYPE_PROCESS, |
| PVRSRV_STAT_TYPE_MEMORY, |
| PVRSRV_STAT_TYPE_RIMEMORY, |
| PVRSRV_STAT_TYPE_CACHEOP, |
| PVRSRV_STAT_TYPE_LAST |
| } PVRSRV_STAT_TYPE; |
| |
| #define SEPARATOR_STR_LEN 166 |
| |
| typedef struct _PVRSRV_STAT_PV_DATA_ { |
| |
| PVRSRV_STAT_TYPE eStatType; |
| PVRSRV_STATS_PRINT_ELEMENTS* pfnStatsPrintElements; |
| IMG_CHAR szLiveStatsHeaderStr[SEPARATOR_STR_LEN + 1]; |
| IMG_CHAR szRetiredStatsHeaderStr[SEPARATOR_STR_LEN + 1]; |
| |
| } PVRSRV_STAT_PV_DATA; |
| |
| static PVRSRV_STAT_PV_DATA g_StatPvDataArr[] = { |
| { PVRSRV_STAT_TYPE_PROCESS, NULL, " Process" , " Process" }, |
| { PVRSRV_STAT_TYPE_MEMORY, NULL, " Memory Allocation" , " Memory Allocation" }, |
| { PVRSRV_STAT_TYPE_RIMEMORY, NULL, " Resource Allocation" , " Resource Allocation" }, |
| { PVRSRV_STAT_TYPE_CACHEOP, NULL, " Cache Maintenance Ops" , " Cache Maintenance Ops" } |
| }; |
| |
| #define GET_STAT_ENTRY_ID(STAT_TYPE) &g_StatPvDataArr[(STAT_TYPE)] |
| |
| /* Generic header strings */ |
| static const IMG_CHAR g_szLiveHeaderStr[] = " Statistics for LIVE Processes "; |
| static const IMG_CHAR g_szRetiredHeaderStr[] = " Statistics for RETIRED Processes "; |
| |
| /* Separator string used for separating stats for different PIDs */ |
| static IMG_CHAR g_szSeparatorStr[SEPARATOR_STR_LEN + 1] = ""; |
| |
| static inline void |
| _prepareStatsHeaderString(IMG_CHAR *pszStatsSpecificStr, const IMG_CHAR* pszGenericHeaderStr) |
| { |
| IMG_UINT32 ui32NumSeparators; |
| IMG_CHAR szStatsHeaderFooterStr[75]; |
| |
| /* Prepare text content of the header in a local string */ |
| strcpy(szStatsHeaderFooterStr, pszStatsSpecificStr); |
| strcat(szStatsHeaderFooterStr, pszGenericHeaderStr); |
| |
| /* Write all '-' characters to the header string */ |
| memset(pszStatsSpecificStr, '-', SEPARATOR_STR_LEN); |
| pszStatsSpecificStr[SEPARATOR_STR_LEN] = '\0'; |
| |
| /* Find the spot for text content in the header string */ |
| ui32NumSeparators = (SEPARATOR_STR_LEN - strlen(szStatsHeaderFooterStr)) >> 1; |
| |
| /* Finally write the text content */ |
| OSSNPrintf(pszStatsSpecificStr + ui32NumSeparators, |
| strlen(szStatsHeaderFooterStr), |
| "%s", szStatsHeaderFooterStr); |
| |
| /* Overwrite the '\0' character added by OSSNPrintf() */ |
| if(strlen(szStatsHeaderFooterStr) > 0) |
| { |
| pszStatsSpecificStr[ui32NumSeparators + strlen(szStatsHeaderFooterStr) - 1] = ' '; |
| } |
| } |
| |
| static inline void |
| _prepareSeparatorStrings(void) |
| { |
| IMG_UINT32 i; |
| |
| /* Prepare header strings for each stat type */ |
| for(i = 0; i < PVRSRV_STAT_TYPE_LAST; ++i) |
| { |
| _prepareStatsHeaderString(g_StatPvDataArr[i].szLiveStatsHeaderStr, g_szLiveHeaderStr); |
| _prepareStatsHeaderString(g_StatPvDataArr[i].szRetiredStatsHeaderStr, g_szRetiredHeaderStr); |
| } |
| |
| /* Prepare separator string to separate stats for different PIDs */ |
| memset(g_szSeparatorStr, '-', SEPARATOR_STR_LEN); |
| g_szSeparatorStr[SEPARATOR_STR_LEN] = '\0'; |
| } |
| |
| static inline void |
| _prepareStatsPrivateData(void) |
| { |
| #if defined(PVRSRV_ENABLE_PERPID_STATS) |
| g_StatPvDataArr[PVRSRV_STAT_TYPE_PROCESS].pfnStatsPrintElements = ProcessStatsPrintElements; |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_MEMORY_STATS) |
| g_StatPvDataArr[PVRSRV_STAT_TYPE_MEMORY].pfnStatsPrintElements = MemStatsPrintElements; |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) |
| g_StatPvDataArr[PVRSRV_STAT_TYPE_RIMEMORY].pfnStatsPrintElements = RIMemStatsPrintElements; |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_CACHEOP_STATS) |
| g_StatPvDataArr[PVRSRV_STAT_TYPE_CACHEOP].pfnStatsPrintElements = CacheOpStatsPrintElements; |
| #endif |
| |
| _prepareSeparatorStrings(); |
| } |
| |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_MEMORY_STATS) |
| static IMPLEMENT_LIST_INSERT(PVRSRV_MEM_ALLOC_REC) |
| static IMPLEMENT_LIST_REMOVE(PVRSRV_MEM_ALLOC_REC) |
| #endif |
| |
| /* |
| * Global Boolean to flag when the statistics are ready to monitor |
| * memory allocations. |
| */ |
| static IMG_BOOL bProcessStatsInitialised = IMG_FALSE; |
| |
| /* |
| * Linked lists for process stats. Live stats are for processes which are still running |
| * and the dead list holds those that have exited. |
| */ |
| static PVRSRV_PROCESS_STATS *g_psLiveList; |
| static PVRSRV_PROCESS_STATS *g_psDeadList; |
| |
| static POS_LOCK g_psLinkedListLock; |
| /* Lockdep feature in the kernel cannot differentiate between different instances of same lock type. |
| * This allows it to group all such instances of the same lock type under one class |
| * The consequence of this is that, if lock acquisition is nested on different instances, it generates |
| * a false warning message about the possible occurrence of deadlock due to recursive lock acquisition. |
| * Hence we create the following sub classes to explicitly appraise Lockdep of such safe lock nesting */ |
| #define PROCESS_LOCK_SUBCLASS_CURRENT 1 |
| #define PROCESS_LOCK_SUBCLASS_PREV 2 |
| #define PROCESS_LOCK_SUBCLASS_NEXT 3 |
| #if defined(ENABLE_DEBUGFS_PIDS) |
| /* |
| * Pointer to OS folder to hold PID folders. |
| */ |
| static void *pvOSProcStatsFolder; |
| #endif |
| #if defined(PVRSRV_ENABLE_MEMTRACK_STATS_FILE) |
| static void *pvOSProcStats; |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) |
| /* global driver PID stats registration handle */ |
| static IMG_HANDLE g_hDriverProcessStats; |
| #endif |
| |
| /* global driver-data folders */ |
| typedef struct _GLOBAL_STATS_ |
| { |
| IMG_UINT32 ui32StatValue[PVRSRV_DRIVER_STAT_TYPE_COUNT]; |
| POS_LOCK hGlobalStatsLock; |
| } GLOBAL_STATS; |
| |
| static void *pvOSGlobalMemEntryRef; |
| static IMG_CHAR* const pszDriverStatFilename = "driver_stats"; |
| static GLOBAL_STATS gsGlobalStats; |
| |
| #define HASH_INITIAL_SIZE 5 |
| /* A hash table used to store the size of any vmalloc'd allocation |
| * against its address (not needed for kmallocs as we can use ksize()) */ |
| static HASH_TABLE* gpsSizeTrackingHashTable; |
| static POS_LOCK gpsSizeTrackingHashTableLock; |
| |
| static PVRSRV_ERROR _RegisterProcess(IMG_HANDLE *phProcessStats, IMG_PID ownerPid); |
| |
| static void _AddProcessStatsToFrontOfDeadList(PVRSRV_PROCESS_STATS* psProcessStats); |
| static void _AddProcessStatsToFrontOfLiveList(PVRSRV_PROCESS_STATS* psProcessStats); |
| static void _RemoveProcessStatsFromList(PVRSRV_PROCESS_STATS* psProcessStats); |
| |
| static void _DestroyProcessStat(PVRSRV_PROCESS_STATS* psProcessStats); |
| |
| static void _DecreaseProcStatValue(PVRSRV_MEM_ALLOC_TYPE eAllocType, |
| PVRSRV_PROCESS_STATS* psProcessStats, |
| IMG_UINT32 uiBytes); |
| /* |
| * Power statistics related definitions |
| */ |
| |
| /* For the mean time, use an exponentially weighted moving average with a |
| * 1/4 weighting for the new measurement. |
| */ |
| #define MEAN_TIME(A, B) ( ((3*(A))/4) + ((1 * (B))/4) ) |
| |
| #define UPDATE_TIME(time, newtime) \ |
| ((time) > 0 ? MEAN_TIME((time),(newtime)) : (newtime)) |
| |
| /* Enum to be used as input to GET_POWER_STAT_INDEX */ |
| typedef enum |
| { |
| DEVICE = 0, |
| SYSTEM = 1, |
| POST_POWER = 0, |
| PRE_POWER = 2, |
| POWER_OFF = 0, |
| POWER_ON = 4, |
| NOT_FORCED = 0, |
| FORCED = 8, |
| } PVRSRV_POWER_STAT_TYPE; |
| |
| /* Macro used to access one of the power timing statistics inside an array */ |
| #define GET_POWER_STAT_INDEX(forced,powon,prepow,system) \ |
| ((forced) + (powon) + (prepow) + (system)) |
| |
| /* For the power timing stats we need 16 variables to store all the |
| * combinations of forced/not forced, power-on/power-off, pre-power/post-power |
| * and device/system statistics |
| */ |
| #define NUM_POWER_STATS (16) |
| static IMG_UINT32 aui32PowerTimingStats[NUM_POWER_STATS]; |
| |
| static void *pvOSPowerStatsEntryData; |
| |
| typedef struct _EXTRA_POWER_STATS_ |
| { |
| IMG_UINT64 ui64PreClockSpeedChangeDuration; |
| IMG_UINT64 ui64BetweenPreEndingAndPostStartingDuration; |
| IMG_UINT64 ui64PostClockSpeedChangeDuration; |
| } EXTRA_POWER_STATS; |
| |
| #define NUM_EXTRA_POWER_STATS 10 |
| |
| static EXTRA_POWER_STATS asClockSpeedChanges[NUM_EXTRA_POWER_STATS]; |
| static IMG_UINT32 ui32ClockSpeedIndexStart, ui32ClockSpeedIndexEnd; |
| |
| |
| #if defined(PVRSRV_ENABLE_PROCESS_STATS) |
| void InsertPowerTimeStatistic(IMG_UINT64 ui64SysStartTime, IMG_UINT64 ui64SysEndTime, |
| IMG_UINT64 ui64DevStartTime, IMG_UINT64 ui64DevEndTime, |
| IMG_BOOL bForced, IMG_BOOL bPowerOn, IMG_BOOL bPrePower) |
| { |
| IMG_UINT32 *pui32Stat; |
| IMG_UINT64 ui64DeviceDiff = ui64DevEndTime - ui64DevStartTime; |
| IMG_UINT64 ui64SystemDiff = ui64SysEndTime - ui64SysStartTime; |
| IMG_UINT32 ui32Index; |
| |
| if (bPrePower) |
| { |
| HTBLOGK(HTB_SF_MAIN_PRE_POWER, bPowerOn, ui64DeviceDiff, ui64SystemDiff); |
| } |
| else |
| { |
| HTBLOGK(HTB_SF_MAIN_POST_POWER, bPowerOn, ui64SystemDiff,ui64DeviceDiff); |
| } |
| |
| ui32Index = GET_POWER_STAT_INDEX(bForced ? FORCED : NOT_FORCED, |
| bPowerOn ? POWER_ON : POWER_OFF, |
| bPrePower ? PRE_POWER : POST_POWER, |
| DEVICE); |
| pui32Stat = &aui32PowerTimingStats[ui32Index]; |
| *pui32Stat = UPDATE_TIME(*pui32Stat, ui64DeviceDiff); |
| |
| ui32Index = GET_POWER_STAT_INDEX(bForced ? FORCED : NOT_FORCED, |
| bPowerOn ? POWER_ON : POWER_OFF, |
| bPrePower ? PRE_POWER : POST_POWER, |
| SYSTEM); |
| pui32Stat = &aui32PowerTimingStats[ui32Index]; |
| *pui32Stat = UPDATE_TIME(*pui32Stat, ui64SystemDiff); |
| } |
| |
| static IMG_UINT64 ui64PreClockSpeedChangeMark; |
| |
| void InsertPowerTimeStatisticExtraPre(IMG_UINT64 ui64StartTimer, IMG_UINT64 ui64Stoptimer) |
| { |
| asClockSpeedChanges[ui32ClockSpeedIndexEnd].ui64PreClockSpeedChangeDuration = ui64Stoptimer - ui64StartTimer; |
| |
| ui64PreClockSpeedChangeMark = OSClockus(); |
| } |
| |
| void InsertPowerTimeStatisticExtraPost(IMG_UINT64 ui64StartTimer, IMG_UINT64 ui64StopTimer) |
| { |
| IMG_UINT64 ui64Duration = ui64StartTimer - ui64PreClockSpeedChangeMark; |
| |
| PVR_ASSERT(ui64PreClockSpeedChangeMark > 0); |
| |
| asClockSpeedChanges[ui32ClockSpeedIndexEnd].ui64BetweenPreEndingAndPostStartingDuration = ui64Duration; |
| asClockSpeedChanges[ui32ClockSpeedIndexEnd].ui64PostClockSpeedChangeDuration = ui64StopTimer - ui64StartTimer; |
| |
| ui32ClockSpeedIndexEnd = (ui32ClockSpeedIndexEnd + 1) % NUM_EXTRA_POWER_STATS; |
| |
| if (ui32ClockSpeedIndexEnd == ui32ClockSpeedIndexStart) |
| { |
| ui32ClockSpeedIndexStart = (ui32ClockSpeedIndexStart + 1) % NUM_EXTRA_POWER_STATS; |
| } |
| |
| ui64PreClockSpeedChangeMark = 0; |
| } |
| #endif |
| |
| /*************************************************************************/ /*! |
| @Function _FindProcessStatsInLiveList |
| @Description Searches the Live Process List for a statistics structure that |
| matches the PID given. |
| @Input pid Process to search for. |
| @Return Pointer to stats structure for the process. |
| */ /**************************************************************************/ |
| static PVRSRV_PROCESS_STATS* |
| _FindProcessStatsInLiveList(IMG_PID pid) |
| { |
| PVRSRV_PROCESS_STATS* psProcessStats = g_psLiveList; |
| |
| while (psProcessStats != NULL) |
| { |
| if (psProcessStats->pid == pid) |
| { |
| return psProcessStats; |
| } |
| |
| psProcessStats = psProcessStats->psNext; |
| } |
| |
| return NULL; |
| } /* _FindProcessStatsInLiveList */ |
| |
| /*************************************************************************/ /*! |
| @Function _FindProcessStatsInDeadList |
| @Description Searches the Dead Process List for a statistics structure that |
| matches the PID given. |
| @Input pid Process to search for. |
| @Return Pointer to stats structure for the process. |
| */ /**************************************************************************/ |
| static PVRSRV_PROCESS_STATS* |
| _FindProcessStatsInDeadList(IMG_PID pid) |
| { |
| PVRSRV_PROCESS_STATS* psProcessStats = g_psDeadList; |
| |
| while (psProcessStats != NULL) |
| { |
| if (psProcessStats->pid == pid) |
| { |
| return psProcessStats; |
| } |
| |
| psProcessStats = psProcessStats->psNext; |
| } |
| |
| return NULL; |
| } /* _FindProcessStatsInDeadList */ |
| |
| /*************************************************************************/ /*! |
| @Function _FindProcessStats |
| @Description Searches the Live and Dead Process Lists for a statistics |
| structure that matches the PID given. |
| @Input pid Process to search for. |
| @Return Pointer to stats structure for the process. |
| */ /**************************************************************************/ |
| static PVRSRV_PROCESS_STATS* |
| _FindProcessStats(IMG_PID pid) |
| { |
| PVRSRV_PROCESS_STATS* psProcessStats = _FindProcessStatsInLiveList(pid); |
| |
| if (psProcessStats == NULL) |
| { |
| psProcessStats = _FindProcessStatsInDeadList(pid); |
| } |
| |
| return psProcessStats; |
| } /* _FindProcessStats */ |
| |
| /*************************************************************************/ /*! |
| @Function _CompressMemoryUsage |
| @Description Reduces memory usage by deleting old statistics data. |
| This function requires that the list lock is not held! |
| */ /**************************************************************************/ |
| static void |
| _CompressMemoryUsage(void) |
| { |
| PVRSRV_PROCESS_STATS* psProcessStats; |
| PVRSRV_PROCESS_STATS* psProcessStatsToBeFreed; |
| IMG_UINT32 ui32ItemsRemaining; |
| |
| /* |
| * We hold the lock whilst checking the list, but we'll release it |
| * before freeing memory (as that will require the lock too)! |
| */ |
| OSLockAcquire(g_psLinkedListLock); |
| |
| /* Check that the dead list is not bigger than the max size... */ |
| psProcessStats = g_psDeadList; |
| psProcessStatsToBeFreed = NULL; |
| ui32ItemsRemaining = MAX_DEAD_LIST_PROCESSES; |
| |
| while (psProcessStats != NULL && ui32ItemsRemaining > 0) |
| { |
| ui32ItemsRemaining--; |
| if (ui32ItemsRemaining == 0) |
| { |
| /* This is the last allowed process, cut the linked list here! */ |
| psProcessStatsToBeFreed = psProcessStats->psNext; |
| psProcessStats->psNext = NULL; |
| } |
| else |
| { |
| psProcessStats = psProcessStats->psNext; |
| } |
| } |
| |
| OSLockRelease(g_psLinkedListLock); |
| |
| /* Any processes stats remaining will need to be destroyed... */ |
| while (psProcessStatsToBeFreed != NULL) |
| { |
| PVRSRV_PROCESS_STATS* psNextProcessStats = psProcessStatsToBeFreed->psNext; |
| |
| psProcessStatsToBeFreed->psNext = NULL; |
| _DestroyProcessStat(psProcessStatsToBeFreed); |
| psProcessStatsToBeFreed = psNextProcessStats; |
| } |
| } /* _CompressMemoryUsage */ |
| |
| /* These functions move the process stats from the live to the dead list. |
| * _MoveProcessToDeadList moves the entry in the global lists and |
| * it needs to be protected by g_psLinkedListLock. |
| * _MoveProcessToDeadListDebugFS performs the OS calls and it |
| * shouldn't be used under g_psLinkedListLock because this could generate a |
| * lockdep warning. */ |
| static void |
| _MoveProcessToDeadList(PVRSRV_PROCESS_STATS* psProcessStats) |
| { |
| /* Take the element out of the live list and append to the dead list... */ |
| _RemoveProcessStatsFromList(psProcessStats); |
| _AddProcessStatsToFrontOfDeadList(psProcessStats); |
| } /* _MoveProcessToDeadList */ |
| |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| /* These functions move the process stats from the dead to the live list. |
| * _MoveProcessToLiveList moves the entry in the global lists and |
| * it needs to be protected by g_psLinkedListLock. |
| * _MoveProcessToLiveListDebugFS performs the OS calls and it |
| * shouldn't be used under g_psLinkedListLock because this could generate a |
| * lockdep warning. */ |
| static void |
| _MoveProcessToLiveList(PVRSRV_PROCESS_STATS* psProcessStats) |
| { |
| /* Take the element out of the live list and append to the dead list... */ |
| _RemoveProcessStatsFromList(psProcessStats); |
| _AddProcessStatsToFrontOfLiveList(psProcessStats); |
| } /* _MoveProcessToLiveList */ |
| #endif |
| |
| /*************************************************************************/ /*! |
| @Function _AddProcessStatsToFrontOfLiveList |
| @Description Add a statistic to the live list head. |
| @Input psProcessStats Process stats to add. |
| */ /**************************************************************************/ |
| static void |
| _AddProcessStatsToFrontOfLiveList(PVRSRV_PROCESS_STATS* psProcessStats) |
| { |
| /* This function should always be called under global list lock g_psLinkedListLock. |
| */ |
| PVR_ASSERT(psProcessStats != NULL); |
| |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| |
| if (g_psLiveList != NULL) |
| { |
| PVR_ASSERT(psProcessStats != g_psLiveList); |
| OSLockAcquireNested(g_psLiveList->hLock, PROCESS_LOCK_SUBCLASS_PREV); |
| g_psLiveList->psPrev = psProcessStats; |
| OSLockRelease(g_psLiveList->hLock); |
| psProcessStats->psNext = g_psLiveList; |
| } |
| |
| g_psLiveList = psProcessStats; |
| |
| OSLockRelease(psProcessStats->hLock); |
| } /* _AddProcessStatsToFrontOfLiveList */ |
| |
| /*************************************************************************/ /*! |
| @Function _AddProcessStatsToFrontOfDeadList |
| @Description Add a statistic to the dead list head. |
| @Input psProcessStats Process stats to add. |
| */ /**************************************************************************/ |
| static void |
| _AddProcessStatsToFrontOfDeadList(PVRSRV_PROCESS_STATS* psProcessStats) |
| { |
| PVR_ASSERT(psProcessStats != NULL); |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| |
| if (g_psDeadList != NULL) |
| { |
| PVR_ASSERT(psProcessStats != g_psDeadList); |
| OSLockAcquireNested(g_psDeadList->hLock, PROCESS_LOCK_SUBCLASS_PREV); |
| g_psDeadList->psPrev = psProcessStats; |
| OSLockRelease(g_psDeadList->hLock); |
| psProcessStats->psNext = g_psDeadList; |
| } |
| |
| g_psDeadList = psProcessStats; |
| |
| OSLockRelease(psProcessStats->hLock); |
| } /* _AddProcessStatsToFrontOfDeadList */ |
| |
| /*************************************************************************/ /*! |
| @Function _RemoveProcessStatsFromList |
| @Description Detaches a process from either the live or dead list. |
| @Input psProcessStats Process stats to remove. |
| */ /**************************************************************************/ |
| static void |
| _RemoveProcessStatsFromList(PVRSRV_PROCESS_STATS* psProcessStats) |
| { |
| PVR_ASSERT(psProcessStats != NULL); |
| |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| |
| /* Remove the item from the linked lists... */ |
| if (g_psLiveList == psProcessStats) |
| { |
| g_psLiveList = psProcessStats->psNext; |
| |
| if (g_psLiveList != NULL) |
| { |
| PVR_ASSERT(psProcessStats != g_psLiveList); |
| OSLockAcquireNested(g_psLiveList->hLock, PROCESS_LOCK_SUBCLASS_PREV); |
| g_psLiveList->psPrev = NULL; |
| OSLockRelease(g_psLiveList->hLock); |
| |
| } |
| } |
| else if (g_psDeadList == psProcessStats) |
| { |
| g_psDeadList = psProcessStats->psNext; |
| |
| if (g_psDeadList != NULL) |
| { |
| PVR_ASSERT(psProcessStats != g_psDeadList); |
| OSLockAcquireNested(g_psDeadList->hLock, PROCESS_LOCK_SUBCLASS_PREV); |
| g_psDeadList->psPrev = NULL; |
| OSLockRelease(g_psDeadList->hLock); |
| } |
| } |
| else |
| { |
| PVRSRV_PROCESS_STATS* psNext = psProcessStats->psNext; |
| PVRSRV_PROCESS_STATS* psPrev = psProcessStats->psPrev; |
| |
| if (psProcessStats->psNext != NULL) |
| { |
| PVR_ASSERT(psProcessStats != psNext); |
| OSLockAcquireNested(psNext->hLock, PROCESS_LOCK_SUBCLASS_NEXT); |
| psProcessStats->psNext->psPrev = psPrev; |
| OSLockRelease(psNext->hLock); |
| } |
| if (psProcessStats->psPrev != NULL) |
| { |
| PVR_ASSERT(psProcessStats != psPrev); |
| OSLockAcquireNested(psPrev->hLock, PROCESS_LOCK_SUBCLASS_PREV); |
| psProcessStats->psPrev->psNext = psNext; |
| OSLockRelease(psPrev->hLock); |
| } |
| } |
| |
| |
| /* Reset the pointers in this cell, as it is not attached to anything */ |
| psProcessStats->psNext = NULL; |
| psProcessStats->psPrev = NULL; |
| |
| OSLockRelease(psProcessStats->hLock); |
| |
| } /* _RemoveProcessStatsFromList */ |
| |
| static PVRSRV_ERROR |
| _AllocateProcessStats(PVRSRV_PROCESS_STATS **ppsProcessStats, IMG_PID ownerPid) |
| { |
| PVRSRV_ERROR eError; |
| PVRSRV_PROCESS_STATS *psProcessStats; |
| |
| psProcessStats = OSAllocZMemNoStats(sizeof(PVRSRV_PROCESS_STATS)); |
| if (psProcessStats == NULL) |
| { |
| return PVRSRV_ERROR_OUT_OF_MEMORY; |
| } |
| |
| psProcessStats->pid = ownerPid; |
| psProcessStats->ui32RefCount = 1; |
| |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_CONNECTIONS] = 1; |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_MAX_CONNECTIONS] = 1; |
| |
| eError = OSLockCreateNoStats(&psProcessStats->hLock); |
| if (eError != PVRSRV_OK) |
| { |
| goto e0; |
| } |
| |
| *ppsProcessStats = psProcessStats; |
| return PVRSRV_OK; |
| |
| e0: |
| OSFreeMemNoStats(psProcessStats); |
| return PVRSRV_ERROR_OUT_OF_MEMORY; |
| } |
| |
| /*************************************************************************/ /*! |
| @Function _DestroyProcessStat |
| @Description Frees memory and resources held by a process statistic. |
| @Input psProcessStats Process stats to destroy. |
| */ /**************************************************************************/ |
| static void |
| _DestroyProcessStat(PVRSRV_PROCESS_STATS* psProcessStats) |
| { |
| PVR_ASSERT(psProcessStats != NULL); |
| |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| |
| /* Free the memory statistics... */ |
| #if defined(PVRSRV_ENABLE_MEMORY_STATS) |
| while (psProcessStats->psMemoryRecords) |
| { |
| List_PVRSRV_MEM_ALLOC_REC_Remove(psProcessStats->psMemoryRecords); |
| } |
| #endif |
| OSLockRelease(psProcessStats->hLock); |
| |
| /*Destroy the lock */ |
| OSLockDestroyNoStats(psProcessStats->hLock); |
| |
| /* Free the memory... */ |
| OSFreeMemNoStats(psProcessStats); |
| } /* _DestroyProcessStat */ |
| |
| #if defined (ENABLE_DEBUGFS_PIDS) |
| static inline void |
| _createStatsFiles(PVRSRV_OS_STAT_ENTRY* psStatsEntries, |
| OS_STATS_PRINT_FUNC* pfnStatsPrint) |
| { |
| #if defined(PVRSRV_ENABLE_PERPID_STATS) |
| psStatsEntries->pvOSProcessStatsEntryData = OSCreateStatisticEntry("process_stats", |
| psStatsEntries->pvOSStatsFolderData, |
| pfnStatsPrint, |
| GET_STAT_ENTRY_ID(PVRSRV_STAT_TYPE_PROCESS)); |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_CACHEOP_STATS) |
| psStatsEntries->pvOSCacheOpStatsEntryData = OSCreateStatisticEntry("cache_ops_exec", |
| psStatsEntries->pvOSStatsFolderData, |
| pfnStatsPrint, |
| GET_STAT_ENTRY_ID(PVRSRV_STAT_TYPE_CACHEOP)); |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_MEMORY_STATS) |
| psStatsEntries->pvOSMemStatsEntryData = OSCreateStatisticEntry("mem_area", |
| psStatsEntries->pvOSStatsFolderData, |
| pfnStatsPrint, |
| GET_STAT_ENTRY_ID(PVRSRV_STAT_TYPE_MEMORY)); |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) |
| psStatsEntries->pvOSRIMemStatsEntryData = OSCreateStatisticEntry("gpu_mem_area", |
| psStatsEntries->pvOSStatsFolderData, |
| pfnStatsPrint, |
| GET_STAT_ENTRY_ID(PVRSRV_STAT_TYPE_RIMEMORY)); |
| #endif |
| } |
| |
| static inline void |
| _createStatisticsEntries(void) |
| { |
| pvOSProcStatsFolder = OSCreateStatisticFolder("proc_stats", NULL); |
| gsLiveStatEntries.pvOSStatsFolderData = OSCreateStatisticFolder("live_pids_stats", pvOSProcStatsFolder); |
| gsRetiredStatEntries.pvOSStatsFolderData = OSCreateStatisticFolder("retired_pids_stats", pvOSProcStatsFolder); |
| |
| _createStatsFiles(&gsLiveStatEntries, GenericStatsPrintElementsLive); |
| _createStatsFiles(&gsRetiredStatEntries, GenericStatsPrintElementsRetired); |
| |
| _prepareStatsPrivateData(); |
| } |
| |
| static inline void |
| _removeStatsFiles(PVRSRV_OS_STAT_ENTRY* psStatsEntries) |
| { |
| #if defined(PVRSRV_ENABLE_PERPID_STATS) |
| OSRemoveStatisticEntry(&psStatsEntries->pvOSProcessStatsEntryData); |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_CACHEOP_STATS) |
| OSRemoveStatisticEntry(&psStatsEntries->pvOSCacheOpStatsEntryData); |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_MEMORY_STATS) |
| OSRemoveStatisticEntry(&psStatsEntries->pvOSMemStatsEntryData); |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) |
| OSRemoveStatisticEntry(&psStatsEntries->pvOSRIMemStatsEntryData); |
| #endif |
| } |
| |
| static inline void |
| _removeStatisticsEntries(void) |
| { |
| _removeStatsFiles(&gsLiveStatEntries); |
| _removeStatsFiles(&gsRetiredStatEntries); |
| |
| OSRemoveStatisticFolder(&(gsLiveStatEntries.pvOSStatsFolderData)); |
| OSRemoveStatisticFolder(&(gsRetiredStatEntries.pvOSStatsFolderData)); |
| OSRemoveStatisticFolder(&pvOSProcStatsFolder); |
| } |
| #endif |
| |
| /*************************************************************************/ /*! |
| @Function PVRSRVStatsInitialise |
| @Description Entry point for initialising the statistics module. |
| @Return Standard PVRSRV_ERROR error code. |
| */ /**************************************************************************/ |
| PVRSRV_ERROR |
| PVRSRVStatsInitialise(void) |
| { |
| PVRSRV_ERROR error; |
| |
| PVR_ASSERT(g_psLiveList == NULL); |
| PVR_ASSERT(g_psDeadList == NULL); |
| PVR_ASSERT(g_psLinkedListLock == NULL); |
| PVR_ASSERT(gpsSizeTrackingHashTable == NULL); |
| PVR_ASSERT(bProcessStatsInitialised == IMG_FALSE); |
| |
| /* We need a lock to protect the linked lists... */ |
| error = OSLockCreate(&g_psLinkedListLock); |
| if (error == PVRSRV_OK) |
| { |
| /* We also need a lock to protect the hash table used for size tracking.. */ |
| error = OSLockCreate(&gpsSizeTrackingHashTableLock); |
| |
| if (error != PVRSRV_OK) |
| { |
| goto e0; |
| } |
| |
| /* We also need a lock to protect the GlobalStat counters */ |
| error = OSLockCreate(&gsGlobalStats.hGlobalStatsLock); |
| if (error != PVRSRV_OK) |
| { |
| goto e1; |
| } |
| |
| #if defined(ENABLE_DEBUGFS_PIDS) |
| _createStatisticsEntries(); |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_MEMTRACK_STATS_FILE) |
| pvOSProcStats = OSCreateRawStatisticEntry("memtrack_stats", NULL, |
| RawProcessStatsPrintElements); |
| #endif |
| |
| /* Create power stats entry... */ |
| pvOSPowerStatsEntryData = OSCreateStatisticEntry("power_timing_stats", |
| NULL, |
| PowerStatsPrintElements, |
| NULL); |
| |
| pvOSGlobalMemEntryRef = OSCreateStatisticEntry(pszDriverStatFilename, |
| NULL, |
| GlobalStatsPrintElements, |
| NULL); |
| |
| /* Flag that we are ready to start monitoring memory allocations. */ |
| |
| gpsSizeTrackingHashTable = HASH_Create(HASH_INITIAL_SIZE); |
| |
| OSCachedMemSet(asClockSpeedChanges, 0, sizeof(asClockSpeedChanges)); |
| |
| bProcessStatsInitialised = IMG_TRUE; |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) |
| /* Register our 'system' PID to hold driver-wide alloc stats */ |
| _RegisterProcess(&g_hDriverProcessStats, PVR_SYS_ALLOC_PID); |
| #endif |
| } |
| return error; |
| e1: |
| OSLockDestroy(gpsSizeTrackingHashTableLock); |
| gpsSizeTrackingHashTableLock = NULL; |
| e0: |
| OSLockDestroy(g_psLinkedListLock); |
| g_psLinkedListLock = NULL; |
| return error; |
| |
| } /* PVRSRVStatsInitialise */ |
| |
| static PVRSRV_ERROR _DumpAllVMallocEntries (uintptr_t k, uintptr_t v); |
| |
| /*************************************************************************/ /*! |
| @Function PVRSRVStatsDestroy |
| @Description Method for destroying the statistics module data. |
| */ /**************************************************************************/ |
| void |
| PVRSRVStatsDestroy(void) |
| { |
| PVR_ASSERT(bProcessStatsInitialised); |
| |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) |
| /* Deregister our 'system' PID which holds driver-wide alloc stats */ |
| PVRSRVStatsDeregisterProcess(g_hDriverProcessStats); |
| #endif |
| |
| /* Stop monitoring memory allocations... */ |
| bProcessStatsInitialised = IMG_FALSE; |
| |
| #if defined(PVRSRV_ENABLE_MEMTRACK_STATS_FILE) |
| if (pvOSProcStats) |
| { |
| OSRemoveRawStatisticEntry(&pvOSProcStats); |
| } |
| #endif |
| |
| /* Destroy the power stats entry... */ |
| if (pvOSPowerStatsEntryData!=NULL) |
| { |
| OSRemoveStatisticEntry(&pvOSPowerStatsEntryData); |
| } |
| |
| /* Destroy the global data entry */ |
| if (pvOSGlobalMemEntryRef!=NULL) |
| { |
| OSRemoveStatisticEntry(&pvOSGlobalMemEntryRef); |
| } |
| |
| #if defined(ENABLE_DEBUGFS_PIDS) |
| _removeStatisticsEntries(); |
| #endif |
| |
| /* Destroy the locks... */ |
| if (g_psLinkedListLock != NULL) |
| { |
| OSLockDestroy(g_psLinkedListLock); |
| g_psLinkedListLock = NULL; |
| } |
| |
| /* Free the live and dead lists... */ |
| while (g_psLiveList != NULL) |
| { |
| PVRSRV_PROCESS_STATS* psProcessStats = g_psLiveList; |
| _RemoveProcessStatsFromList(psProcessStats); |
| _DestroyProcessStat(psProcessStats); |
| } |
| |
| while (g_psDeadList != NULL) |
| { |
| PVRSRV_PROCESS_STATS* psProcessStats = g_psDeadList; |
| _RemoveProcessStatsFromList(psProcessStats); |
| _DestroyProcessStat(psProcessStats); |
| } |
| |
| if (gpsSizeTrackingHashTable != NULL) |
| { |
| /* Dump all remaining entries in HASH table (list any remaining vmallocs) */ |
| HASH_Iterate(gpsSizeTrackingHashTable, (HASH_pfnCallback)_DumpAllVMallocEntries); |
| HASH_Delete(gpsSizeTrackingHashTable); |
| } |
| if (gpsSizeTrackingHashTableLock != NULL) |
| { |
| OSLockDestroy(gpsSizeTrackingHashTableLock); |
| gpsSizeTrackingHashTableLock = NULL; |
| } |
| |
| if (NULL != gsGlobalStats.hGlobalStatsLock) |
| { |
| OSLockDestroy(gsGlobalStats.hGlobalStatsLock); |
| gsGlobalStats.hGlobalStatsLock = NULL; |
| } |
| |
| } /* PVRSRVStatsDestroy */ |
| |
| static void _decrease_global_stat(PVRSRV_MEM_ALLOC_TYPE eAllocType, |
| size_t uiBytes) |
| { |
| OSLockAcquire(gsGlobalStats.hGlobalStatsLock); |
| |
| switch (eAllocType) |
| { |
| #if !defined(PVR_DISABLE_KMALLOC_MEMSTATS) |
| case PVRSRV_MEM_ALLOC_TYPE_KMALLOC: |
| DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_KMALLOC, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_VMALLOC: |
| DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_VMALLOC, uiBytes); |
| break; |
| #else |
| case PVRSRV_MEM_ALLOC_TYPE_KMALLOC: |
| case PVRSRV_MEM_ALLOC_TYPE_VMALLOC: |
| break; |
| #endif |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_UMA: |
| DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_ALLOC_PT_MEMORY_UMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA: |
| DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_VMAP_PT_UMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_LMA: |
| DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_ALLOC_PT_MEMORY_LMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_IOREMAP_PT_LMA: |
| DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_IOREMAP_PT_LMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_LMA_PAGES: |
| DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_ALLOC_GPUMEM_LMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_UMA_PAGES: |
| DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_ALLOC_GPUMEM_UMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_MAP_UMA_LMA_PAGES: |
| DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_MAPPED_GPUMEM_UMA_LMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_UMA_POOL_PAGES: |
| DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_ALLOC_GPUMEM_UMA_POOL, uiBytes); |
| break; |
| |
| default: |
| PVR_ASSERT(0); |
| break; |
| } |
| OSLockRelease(gsGlobalStats.hGlobalStatsLock); |
| } |
| |
| static void _increase_global_stat(PVRSRV_MEM_ALLOC_TYPE eAllocType, |
| size_t uiBytes) |
| { |
| OSLockAcquire(gsGlobalStats.hGlobalStatsLock); |
| |
| switch (eAllocType) |
| { |
| #if !defined(PVR_DISABLE_KMALLOC_MEMSTATS) |
| case PVRSRV_MEM_ALLOC_TYPE_KMALLOC: |
| INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_KMALLOC, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_VMALLOC: |
| INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_VMALLOC, uiBytes); |
| break; |
| #else |
| case PVRSRV_MEM_ALLOC_TYPE_KMALLOC: |
| case PVRSRV_MEM_ALLOC_TYPE_VMALLOC: |
| break; |
| #endif |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_UMA: |
| INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_ALLOC_PT_MEMORY_UMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA: |
| INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_VMAP_PT_UMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_LMA: |
| INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_ALLOC_PT_MEMORY_LMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_IOREMAP_PT_LMA: |
| INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_IOREMAP_PT_LMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_LMA_PAGES: |
| INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_ALLOC_GPUMEM_LMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_UMA_PAGES: |
| INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_ALLOC_GPUMEM_UMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_MAP_UMA_LMA_PAGES: |
| INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_MAPPED_GPUMEM_UMA_LMA, uiBytes); |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_UMA_POOL_PAGES: |
| INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats, PVRSRV_DRIVER_STAT_TYPE_ALLOC_GPUMEM_UMA_POOL, uiBytes); |
| break; |
| |
| default: |
| PVR_ASSERT(0); |
| break; |
| } |
| OSLockRelease(gsGlobalStats.hGlobalStatsLock); |
| } |
| |
| static PVRSRV_ERROR |
| _RegisterProcess(IMG_HANDLE *phProcessStats, IMG_PID ownerPid) |
| { |
| PVRSRV_PROCESS_STATS* psProcessStats=NULL; |
| PVRSRV_ERROR eError; |
| |
| PVR_ASSERT(phProcessStats != NULL); |
| |
| PVR_DPF((PVR_DBG_MESSAGE, "%s: Register process PID %d [%s]", |
| __func__, ownerPid, (ownerPid == PVR_SYS_ALLOC_PID) |
| ? "system" : OSGetCurrentClientProcessNameKM())); |
| |
| /* Check the PID has not already moved to the dead list... */ |
| OSLockAcquire(g_psLinkedListLock); |
| psProcessStats = _FindProcessStatsInDeadList(ownerPid); |
| if (psProcessStats != NULL) |
| { |
| /* Move it back onto the live list! */ |
| _RemoveProcessStatsFromList(psProcessStats); |
| _AddProcessStatsToFrontOfLiveList(psProcessStats); |
| } |
| else |
| { |
| /* Check the PID is not already registered in the live list... */ |
| psProcessStats = _FindProcessStatsInLiveList(ownerPid); |
| } |
| |
| /* If the PID is on the live list then just increment the ref count and return... */ |
| if (psProcessStats != NULL) |
| { |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| |
| psProcessStats->ui32RefCount++; |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_CONNECTIONS] = psProcessStats->ui32RefCount; |
| UPDATE_MAX_VALUE(psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_MAX_CONNECTIONS], |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_CONNECTIONS]); |
| OSLockRelease(psProcessStats->hLock); |
| OSLockRelease(g_psLinkedListLock); |
| |
| *phProcessStats = psProcessStats; |
| |
| return PVRSRV_OK; |
| } |
| OSLockRelease(g_psLinkedListLock); |
| |
| /* Allocate a new node structure and initialise it... */ |
| eError = _AllocateProcessStats(&psProcessStats, ownerPid); |
| if(eError != PVRSRV_OK) |
| { |
| goto e0; |
| } |
| |
| /* Add it to the live list... */ |
| OSLockAcquire(g_psLinkedListLock); |
| _AddProcessStatsToFrontOfLiveList(psProcessStats); |
| OSLockRelease(g_psLinkedListLock); |
| |
| /* Done */ |
| *phProcessStats = (IMG_HANDLE) psProcessStats; |
| |
| return PVRSRV_OK; |
| |
| e0: |
| *phProcessStats = (IMG_HANDLE) NULL; |
| return PVRSRV_ERROR_OUT_OF_MEMORY; |
| } /* _RegisterProcess */ |
| |
| /*************************************************************************/ /*! |
| @Function PVRSRVStatsRegisterProcess |
| @Description Register a process into the list statistics list. |
| @Output phProcessStats Handle to the process to be used to deregister. |
| @Return Standard PVRSRV_ERROR error code. |
| */ /**************************************************************************/ |
| PVRSRV_ERROR |
| PVRSRVStatsRegisterProcess(IMG_HANDLE* phProcessStats) |
| { |
| return _RegisterProcess(phProcessStats, OSGetCurrentClientProcessIDKM()); |
| } |
| |
| /*************************************************************************/ /*! |
| @Function PVRSRVStatsDeregisterProcess |
| @Input hProcessStats Handle to the process returned when registered. |
| @Description Method for destroying the statistics module data. |
| */ /**************************************************************************/ |
| void |
| PVRSRVStatsDeregisterProcess(IMG_HANDLE hProcessStats) |
| { |
| PVR_DPF((PVR_DBG_MESSAGE, "%s: Deregister process entered PID %d [%s]", |
| __func__, OSGetCurrentClientProcessIDKM(), |
| OSGetCurrentProcessName())); |
| |
| if (hProcessStats != (IMG_HANDLE) NULL) |
| { |
| PVRSRV_PROCESS_STATS* psProcessStats = (PVRSRV_PROCESS_STATS*) hProcessStats; |
| |
| /* Lower the reference count, if zero then move it to the dead list */ |
| OSLockAcquire(g_psLinkedListLock); |
| if (psProcessStats->ui32RefCount > 0) |
| { |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| psProcessStats->ui32RefCount--; |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_CONNECTIONS] = psProcessStats->ui32RefCount; |
| |
| #if !defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| if (psProcessStats->ui32RefCount == 0) |
| { |
| OSLockRelease(psProcessStats->hLock); |
| _MoveProcessToDeadList(psProcessStats); |
| }else |
| #endif |
| { |
| OSLockRelease(psProcessStats->hLock); |
| } |
| } |
| OSLockRelease(g_psLinkedListLock); |
| |
| /* Check if the dead list needs to be reduced */ |
| _CompressMemoryUsage(); |
| } |
| } /* PVRSRVStatsDeregisterProcess */ |
| |
| void |
| PVRSRVStatsAddMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE eAllocType, |
| void *pvCpuVAddr, |
| IMG_CPU_PHYADDR sCpuPAddr, |
| size_t uiBytes, |
| void *pvPrivateData, |
| IMG_PID currentPid) |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) && defined(DEBUG) |
| { |
| _PVRSRVStatsAddMemAllocRecord(eAllocType, pvCpuVAddr, sCpuPAddr, uiBytes, pvPrivateData, currentPid, NULL, 0); |
| } |
| void |
| |
| _PVRSRVStatsAddMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE eAllocType, |
| void *pvCpuVAddr, |
| IMG_CPU_PHYADDR sCpuPAddr, |
| size_t uiBytes, |
| void *pvPrivateData, |
| IMG_PID currentPid, |
| void *pvAllocFromFile, IMG_UINT32 ui32AllocFromLine) |
| #endif |
| { |
| #if defined(PVRSRV_ENABLE_MEMORY_STATS) |
| IMG_PID currentCleanupPid = PVRSRVGetPurgeConnectionPid(); |
| PVRSRV_DATA* psPVRSRVData = PVRSRVGetPVRSRVData(); |
| PVRSRV_MEM_ALLOC_REC* psRecord = NULL; |
| PVRSRV_PROCESS_STATS* psProcessStats; |
| enum { PVRSRV_PROC_NOTFOUND, |
| PVRSRV_PROC_FOUND, |
| PVRSRV_PROC_RESURRECTED |
| } eProcSearch = PVRSRV_PROC_FOUND; |
| |
| /* Don't do anything if we are not initialised or we are shutting down! */ |
| if (!bProcessStatsInitialised) |
| { |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: Called when process statistics module is not initialised", |
| __func__)); |
| #endif |
| return; |
| } |
| |
| /* |
| * To prevent a recursive loop, we make the memory allocations for our |
| * memstat records via OSAllocMemNoStats(), which does not try to |
| * create a memstat record entry. |
| */ |
| |
| /* Allocate the memory record... */ |
| psRecord = OSAllocZMemNoStats(sizeof(PVRSRV_MEM_ALLOC_REC)); |
| if (psRecord == NULL) |
| { |
| return; |
| } |
| |
| psRecord->eAllocType = eAllocType; |
| psRecord->pvCpuVAddr = pvCpuVAddr; |
| psRecord->sCpuPAddr.uiAddr = sCpuPAddr.uiAddr; |
| psRecord->uiBytes = uiBytes; |
| psRecord->pvPrivateData = pvPrivateData; |
| |
| psRecord->pid = currentPid; |
| |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) && defined(DEBUG) |
| psRecord->pvAllocdFromFile = pvAllocFromFile; |
| psRecord->ui32AllocdFromLine = ui32AllocFromLine; |
| #endif |
| |
| _increase_global_stat(eAllocType, uiBytes); |
| /* Lock while we find the correct process... */ |
| OSLockAcquire(g_psLinkedListLock); |
| |
| if (psPVRSRVData) |
| { |
| if ((currentPid == psPVRSRVData->cleanupThreadPid) && |
| (currentCleanupPid != 0)) |
| { |
| psProcessStats = _FindProcessStats(currentCleanupPid); |
| } |
| else |
| { |
| psProcessStats = _FindProcessStatsInLiveList(currentPid); |
| if (!psProcessStats) |
| { |
| psProcessStats = _FindProcessStatsInDeadList(currentPid); |
| eProcSearch = PVRSRV_PROC_RESURRECTED; |
| } |
| } |
| } |
| else |
| { |
| psProcessStats = _FindProcessStatsInLiveList(currentPid); |
| if (!psProcessStats) |
| { |
| psProcessStats = _FindProcessStatsInDeadList(currentPid); |
| eProcSearch = PVRSRV_PROC_RESURRECTED; |
| } |
| } |
| |
| if (psProcessStats == NULL) |
| { |
| eProcSearch = PVRSRV_PROC_NOTFOUND; |
| |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: Process stat increment called for 'unknown' process PID(%d)", |
| __func__, currentPid)); |
| |
| if(_AllocateProcessStats(&psProcessStats, currentPid) != PVRSRV_OK) |
| { |
| OSLockRelease(g_psLinkedListLock); |
| goto e0; |
| } |
| |
| /* Add it to the live list... */ |
| _AddProcessStatsToFrontOfLiveList(psProcessStats); |
| |
| OSLockRelease(g_psLinkedListLock); |
| |
| #else /* defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) */ |
| OSLockRelease(g_psLinkedListLock); |
| #endif /* defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) */ |
| |
| if (psProcessStats == NULL) |
| { |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s UNABLE TO CREATE process_stats entry for pid %d [%s] (" IMG_SIZE_FMTSPEC " bytes)", |
| __func__, currentPid, OSGetCurrentProcessName(), uiBytes)); |
| #endif |
| if (psRecord != NULL) |
| { |
| OSFreeMemNoStats(psRecord); |
| } |
| return; |
| } |
| } |
| else |
| { |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| if (eProcSearch == PVRSRV_PROC_RESURRECTED) |
| { |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: Process stat incremented on 'dead' process PID(%d)", |
| __func__, currentPid)); |
| /* Move process from dead list to live list */ |
| _MoveProcessToLiveList(psProcessStats); |
| } |
| #endif |
| OSLockRelease(g_psLinkedListLock); |
| } |
| |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| |
| /* Insert the memory record... */ |
| if (psRecord != NULL) |
| { |
| List_PVRSRV_MEM_ALLOC_REC_Insert(&psProcessStats->psMemoryRecords, psRecord); |
| } |
| |
| /* Update the memory watermarks... */ |
| switch (eAllocType) |
| { |
| #if !defined(PVR_DISABLE_KMALLOC_MEMSTATS) |
| case PVRSRV_MEM_ALLOC_TYPE_KMALLOC: |
| { |
| if (psRecord != NULL) |
| { |
| if (pvCpuVAddr == NULL) |
| { |
| break; |
| } |
| psRecord->ui64Key = (IMG_UINT64)(uintptr_t)pvCpuVAddr; |
| } |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_KMALLOC, (IMG_UINT32)uiBytes); |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_KMALLOC-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_VMALLOC: |
| { |
| if (psRecord != NULL) |
| { |
| if (pvCpuVAddr == NULL) |
| { |
| break; |
| } |
| psRecord->ui64Key = (IMG_UINT64)(uintptr_t)pvCpuVAddr; |
| } |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_VMALLOC, (IMG_UINT32)uiBytes); |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_VMALLOC-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| #else |
| case PVRSRV_MEM_ALLOC_TYPE_KMALLOC: |
| case PVRSRV_MEM_ALLOC_TYPE_VMALLOC: |
| break; |
| #endif |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_UMA: |
| { |
| if (psRecord != NULL) |
| { |
| if (pvCpuVAddr == NULL) |
| { |
| break; |
| } |
| psRecord->ui64Key = (IMG_UINT64)(uintptr_t)pvCpuVAddr; |
| } |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_UMA, (IMG_UINT32)uiBytes); |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_UMA-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA: |
| { |
| if (psRecord != NULL) |
| { |
| if (pvCpuVAddr == NULL) |
| { |
| break; |
| } |
| psRecord->ui64Key = (IMG_UINT64)(uintptr_t)pvCpuVAddr; |
| } |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_VMAP_PT_UMA, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_VMAP_PT_UMA-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_LMA: |
| { |
| if (psRecord != NULL) |
| { |
| psRecord->ui64Key = sCpuPAddr.uiAddr; |
| } |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_LMA, (IMG_UINT32)uiBytes); |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_LMA-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_IOREMAP_PT_LMA: |
| { |
| if (psRecord != NULL) |
| { |
| if (pvCpuVAddr == NULL) |
| { |
| break; |
| } |
| psRecord->ui64Key = (IMG_UINT64)(uintptr_t)pvCpuVAddr; |
| } |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_IOREMAP_PT_LMA, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_IOREMAP_PT_LMA-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_LMA_PAGES: |
| { |
| if (psRecord != NULL) |
| { |
| psRecord->ui64Key = sCpuPAddr.uiAddr; |
| } |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES, (IMG_UINT32)uiBytes); |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_UMA_PAGES: |
| { |
| if (psRecord != NULL) |
| { |
| psRecord->ui64Key = sCpuPAddr.uiAddr; |
| } |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_ALLOC_UMA_PAGES, (IMG_UINT32)uiBytes); |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_ALLOC_UMA_PAGES-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_MAP_UMA_LMA_PAGES: |
| { |
| if (psRecord != NULL) |
| { |
| if (pvCpuVAddr == NULL) |
| { |
| break; |
| } |
| psRecord->ui64Key = (IMG_UINT64)(uintptr_t)pvCpuVAddr; |
| } |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_MAP_UMA_LMA_PAGES, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_MAP_UMA_LMA_PAGES-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| default: |
| { |
| PVR_ASSERT(0); |
| } |
| break; |
| } |
| OSLockRelease(psProcessStats->hLock); |
| |
| return; |
| |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| e0: |
| OSFreeMemNoStats(psRecord); |
| return; |
| #endif |
| #endif |
| } /* PVRSRVStatsAddMemAllocRecord */ |
| |
| void |
| PVRSRVStatsRemoveMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE eAllocType, |
| IMG_UINT64 ui64Key, |
| IMG_PID currentPid) |
| { |
| #if defined(PVRSRV_ENABLE_MEMORY_STATS) |
| IMG_PID currentCleanupPid = PVRSRVGetPurgeConnectionPid(); |
| PVRSRV_DATA* psPVRSRVData = PVRSRVGetPVRSRVData(); |
| PVRSRV_PROCESS_STATS* psProcessStats = NULL; |
| PVRSRV_MEM_ALLOC_REC* psRecord = NULL; |
| IMG_BOOL bFound = IMG_FALSE; |
| |
| /* Don't do anything if we are not initialised or we are shutting down! */ |
| if (!bProcessStatsInitialised) |
| { |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: Called when process statistics module is not initialised", |
| __func__)); |
| #endif |
| return; |
| } |
| |
| /* Lock while we find the correct process and remove this record... */ |
| OSLockAcquire(g_psLinkedListLock); |
| |
| if (psPVRSRVData) |
| { |
| if ((currentPid == psPVRSRVData->cleanupThreadPid) && |
| (currentCleanupPid != 0)) |
| { |
| psProcessStats = _FindProcessStats(currentCleanupPid); |
| } |
| else |
| { |
| psProcessStats = _FindProcessStats(currentPid); |
| } |
| } |
| else |
| { |
| psProcessStats = _FindProcessStats(currentPid); |
| } |
| if (psProcessStats != NULL) |
| { |
| psRecord = psProcessStats->psMemoryRecords; |
| while (psRecord != NULL) |
| { |
| if (psRecord->ui64Key == ui64Key && psRecord->eAllocType == eAllocType) |
| { |
| bFound = IMG_TRUE; |
| break; |
| } |
| |
| psRecord = psRecord->psNext; |
| } |
| } |
| |
| /* If not found, we need to do a full search in case it was allocated to a different PID... */ |
| if (!bFound) |
| { |
| PVRSRV_PROCESS_STATS* psProcessStatsAlreadyChecked = psProcessStats; |
| |
| /* Search all live lists first... */ |
| psProcessStats = g_psLiveList; |
| while (psProcessStats != NULL) |
| { |
| if (psProcessStats != psProcessStatsAlreadyChecked) |
| { |
| psRecord = psProcessStats->psMemoryRecords; |
| while (psRecord != NULL) |
| { |
| if (psRecord->ui64Key == ui64Key && psRecord->eAllocType == eAllocType) |
| { |
| bFound = IMG_TRUE; |
| break; |
| } |
| |
| psRecord = psRecord->psNext; |
| } |
| } |
| |
| if (bFound) |
| { |
| break; |
| } |
| |
| psProcessStats = psProcessStats->psNext; |
| } |
| |
| /* If not found, then search all dead lists next... */ |
| if (!bFound) |
| { |
| psProcessStats = g_psDeadList; |
| while (psProcessStats != NULL) |
| { |
| if (psProcessStats != psProcessStatsAlreadyChecked) |
| { |
| psRecord = psProcessStats->psMemoryRecords; |
| while (psRecord != NULL) |
| { |
| if (psRecord->ui64Key == ui64Key && psRecord->eAllocType == eAllocType) |
| { |
| bFound = IMG_TRUE; |
| break; |
| } |
| |
| psRecord = psRecord->psNext; |
| } |
| } |
| |
| if (bFound) |
| { |
| break; |
| } |
| |
| psProcessStats = psProcessStats->psNext; |
| } |
| } |
| } |
| |
| /* Update the watermark and remove this record...*/ |
| if (bFound) |
| { |
| _decrease_global_stat(eAllocType, psRecord->uiBytes); |
| |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| |
| _DecreaseProcStatValue(eAllocType, |
| psProcessStats, |
| psRecord->uiBytes); |
| |
| List_PVRSRV_MEM_ALLOC_REC_Remove(psRecord); |
| OSLockRelease(psProcessStats->hLock); |
| OSLockRelease(g_psLinkedListLock); |
| |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| /* If all stats are now zero, remove the entry for this thread */ |
| if (psProcessStats->ui32StatAllocFlags == 0) |
| { |
| OSLockAcquire(g_psLinkedListLock); |
| _MoveProcessToDeadList(psProcessStats); |
| OSLockRelease(g_psLinkedListLock); |
| |
| /* Check if the dead list needs to be reduced */ |
| _CompressMemoryUsage(); |
| } |
| #endif |
| /* |
| * Free the record outside the lock so we don't deadlock and so we |
| * reduce the time the lock is held. |
| */ |
| OSFreeMemNoStats(psRecord); |
| } |
| else |
| { |
| OSLockRelease(g_psLinkedListLock); |
| } |
| |
| #else |
| PVR_UNREFERENCED_PARAMETER(eAllocType); |
| PVR_UNREFERENCED_PARAMETER(ui64Key); |
| #endif |
| } /* PVRSRVStatsRemoveMemAllocRecord */ |
| |
| static PVRSRV_ERROR _DumpAllVMallocEntries (uintptr_t k, uintptr_t v) |
| { |
| #if defined(PVRSRV_NEED_PVR_DPF) || defined(DOXYGEN) |
| _PVR_STATS_TRACKING_HASH_ENTRY *psNewTrackingHashEntry = (_PVR_STATS_TRACKING_HASH_ENTRY *)(uintptr_t)v; |
| IMG_UINT64 uiCpuVAddr = (IMG_UINT64)k; |
| |
| PVR_DPF((PVR_DBG_ERROR, "%s: " IMG_SIZE_FMTSPEC " bytes @ 0x%" IMG_UINT64_FMTSPECx " (PID %u)", __func__, |
| psNewTrackingHashEntry->uiSizeInBytes, |
| uiCpuVAddr, |
| psNewTrackingHashEntry->uiPid)); |
| #endif |
| return PVRSRV_OK; |
| } |
| |
| void |
| PVRSRVStatsIncrMemAllocStatAndTrack(PVRSRV_MEM_ALLOC_TYPE eAllocType, |
| size_t uiBytes, |
| IMG_UINT64 uiCpuVAddr, |
| IMG_PID uiPid) |
| { |
| IMG_BOOL bRes = IMG_FALSE; |
| _PVR_STATS_TRACKING_HASH_ENTRY *psNewTrackingHashEntry = NULL; |
| |
| if (!bProcessStatsInitialised || (gpsSizeTrackingHashTable == NULL)) |
| { |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: Called when process statistics module is not initialised", |
| __func__)); |
| #endif |
| return; |
| } |
| |
| /* Alloc untracked memory for the new hash table entry */ |
| psNewTrackingHashEntry = (_PVR_STATS_TRACKING_HASH_ENTRY *)OSAllocMemNoStats(sizeof(*psNewTrackingHashEntry)); |
| if (psNewTrackingHashEntry) |
| { |
| /* Fill-in the size of the allocation and PID of the allocating process */ |
| psNewTrackingHashEntry->uiSizeInBytes = uiBytes; |
| psNewTrackingHashEntry->uiPid = uiPid; |
| OSLockAcquire(gpsSizeTrackingHashTableLock); |
| /* Insert address of the new struct into the hash table */ |
| bRes = HASH_Insert(gpsSizeTrackingHashTable, uiCpuVAddr, (uintptr_t)psNewTrackingHashEntry); |
| OSLockRelease(gpsSizeTrackingHashTableLock); |
| } |
| |
| if (psNewTrackingHashEntry) |
| { |
| if (bRes) |
| { |
| PVRSRVStatsIncrMemAllocStat(eAllocType, uiBytes, uiPid); |
| } |
| else |
| { |
| PVR_DPF((PVR_DBG_ERROR, "*** %s : @ line %d HASH_Insert() failed!", |
| __func__, __LINE__)); |
| } |
| } |
| else |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "*** %s : @ line %d Failed to alloc memory for psNewTrackingHashEntry!", |
| __func__, __LINE__)); |
| } |
| } |
| |
| void |
| PVRSRVStatsIncrMemAllocStat(PVRSRV_MEM_ALLOC_TYPE eAllocType, |
| size_t uiBytes, |
| IMG_PID currentPid) |
| |
| { |
| IMG_PID currentCleanupPid = PVRSRVGetPurgeConnectionPid(); |
| PVRSRV_DATA* psPVRSRVData = PVRSRVGetPVRSRVData(); |
| PVRSRV_PROCESS_STATS* psProcessStats = NULL; |
| enum { PVRSRV_PROC_NOTFOUND, |
| PVRSRV_PROC_FOUND, |
| PVRSRV_PROC_RESURRECTED |
| } eProcSearch = PVRSRV_PROC_FOUND; |
| |
| /* Don't do anything if we are not initialised or we are shutting down! */ |
| if (!bProcessStatsInitialised) |
| { |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: Called when process statistics module is not initialised", |
| __func__)); |
| #endif |
| return; |
| } |
| |
| _increase_global_stat(eAllocType, uiBytes); |
| OSLockAcquire(g_psLinkedListLock); |
| if (psPVRSRVData) |
| { |
| if ((currentPid == psPVRSRVData->cleanupThreadPid) && |
| (currentCleanupPid != 0)) |
| { |
| psProcessStats = _FindProcessStats(currentCleanupPid); |
| } |
| else |
| { |
| psProcessStats = _FindProcessStatsInLiveList(currentPid); |
| if (!psProcessStats) |
| { |
| psProcessStats = _FindProcessStatsInDeadList(currentPid); |
| eProcSearch = PVRSRV_PROC_RESURRECTED; |
| } |
| } |
| } |
| else |
| { |
| psProcessStats = _FindProcessStatsInLiveList(currentPid); |
| if (!psProcessStats) |
| { |
| psProcessStats = _FindProcessStatsInDeadList(currentPid); |
| eProcSearch = PVRSRV_PROC_RESURRECTED; |
| } |
| } |
| |
| if (psProcessStats == NULL) |
| { |
| eProcSearch = PVRSRV_PROC_NOTFOUND; |
| |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: Process stat increment called for 'unknown' process PID(%d)", |
| __func__, currentPid)); |
| |
| if (bProcessStatsInitialised) |
| { |
| if(_AllocateProcessStats(&psProcessStats, currentPid) != PVRSRV_OK) |
| { |
| return; |
| } |
| |
| /* Add it to the live list... */ |
| _AddProcessStatsToFrontOfLiveList(psProcessStats); |
| } |
| #else |
| OSLockRelease(g_psLinkedListLock); |
| #endif /* defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) */ |
| |
| } |
| |
| if (psProcessStats != NULL) |
| { |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| if (eProcSearch == PVRSRV_PROC_RESURRECTED) |
| { |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: Process stat incremented on 'dead' process PID(%d)", |
| __func__, currentPid)); |
| |
| /* Move process from dead list to live list */ |
| _MoveProcessToLiveList(psProcessStats); |
| } |
| #endif |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| /*Release the list lock as soon as we acquire the process lock, |
| * this ensures if the process is in deadlist the entry cannot be deleted or modified */ |
| OSLockRelease(g_psLinkedListLock); |
| /* Update the memory watermarks... */ |
| switch (eAllocType) |
| { |
| #if !defined(PVR_DISABLE_KMALLOC_MEMSTATS) |
| case PVRSRV_MEM_ALLOC_TYPE_KMALLOC: |
| { |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_KMALLOC, (IMG_UINT32)uiBytes); |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_KMALLOC-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_VMALLOC: |
| { |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_VMALLOC, (IMG_UINT32)uiBytes); |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_VMALLOC-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| #else |
| case PVRSRV_MEM_ALLOC_TYPE_KMALLOC: |
| case PVRSRV_MEM_ALLOC_TYPE_VMALLOC: |
| break; |
| #endif |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_UMA: |
| { |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_UMA, (IMG_UINT32)uiBytes); |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_UMA-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA: |
| { |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_VMAP_PT_UMA, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_VMAP_PT_UMA-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_LMA: |
| { |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_LMA, (IMG_UINT32)uiBytes); |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_LMA-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_IOREMAP_PT_LMA: |
| { |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_IOREMAP_PT_LMA, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_IOREMAP_PT_LMA-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_LMA_PAGES: |
| { |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES, (IMG_UINT32)uiBytes); |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_UMA_PAGES: |
| { |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_ALLOC_UMA_PAGES, (IMG_UINT32)uiBytes); |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_ALLOC_UMA_PAGES-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_MAP_UMA_LMA_PAGES: |
| { |
| INCREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_MAP_UMA_LMA_PAGES, (IMG_UINT32)uiBytes); |
| psProcessStats->ui32StatAllocFlags |= (IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_MAP_UMA_LMA_PAGES-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| break; |
| |
| default: |
| { |
| PVR_ASSERT(0); |
| } |
| break; |
| } |
| OSLockRelease(psProcessStats->hLock); |
| } |
| |
| } |
| |
| static void |
| _DecreaseProcStatValue(PVRSRV_MEM_ALLOC_TYPE eAllocType, |
| PVRSRV_PROCESS_STATS* psProcessStats, |
| IMG_UINT32 uiBytes) |
| { |
| switch (eAllocType) |
| { |
| #if !defined(PVR_DISABLE_KMALLOC_MEMSTATS) |
| case PVRSRV_MEM_ALLOC_TYPE_KMALLOC: |
| { |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_KMALLOC, (IMG_UINT32)uiBytes); |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| if (psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_KMALLOC] == 0) |
| { |
| psProcessStats->ui32StatAllocFlags &= ~(IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_KMALLOC-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_VMALLOC: |
| { |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_VMALLOC, (IMG_UINT32)uiBytes); |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| if (psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_VMALLOC] == 0) |
| { |
| psProcessStats->ui32StatAllocFlags &= ~(IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_VMALLOC-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| } |
| break; |
| #else |
| case PVRSRV_MEM_ALLOC_TYPE_KMALLOC: |
| case PVRSRV_MEM_ALLOC_TYPE_VMALLOC: |
| break; |
| #endif |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_UMA: |
| { |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_UMA, (IMG_UINT32)uiBytes); |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| if (psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_UMA] == 0) |
| { |
| psProcessStats->ui32StatAllocFlags &= ~(IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_UMA-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA: |
| { |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_VMAP_PT_UMA, (IMG_UINT32)uiBytes); |
| if (psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_VMAP_PT_UMA] == 0) |
| { |
| psProcessStats->ui32StatAllocFlags &= ~(IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_VMAP_PT_UMA-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_LMA: |
| { |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_LMA, (IMG_UINT32)uiBytes); |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| if (psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_LMA] == 0) |
| { |
| psProcessStats->ui32StatAllocFlags &= ~(IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_LMA-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_IOREMAP_PT_LMA: |
| { |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_IOREMAP_PT_LMA, (IMG_UINT32)uiBytes); |
| if (psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_IOREMAP_PT_LMA] == 0) |
| { |
| psProcessStats->ui32StatAllocFlags &= ~(IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_IOREMAP_PT_LMA-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_LMA_PAGES: |
| { |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES, (IMG_UINT32)uiBytes); |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| if (psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES] == 0) |
| { |
| psProcessStats->ui32StatAllocFlags &= ~(IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_UMA_PAGES: |
| { |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_ALLOC_UMA_PAGES, (IMG_UINT32)uiBytes); |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, (IMG_UINT32)uiBytes); |
| if (psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ALLOC_UMA_PAGES] == 0) |
| { |
| psProcessStats->ui32StatAllocFlags &= ~(IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_ALLOC_UMA_PAGES-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| } |
| break; |
| |
| case PVRSRV_MEM_ALLOC_TYPE_MAP_UMA_LMA_PAGES: |
| { |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_MAP_UMA_LMA_PAGES, (IMG_UINT32)uiBytes); |
| if (psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_MAP_UMA_LMA_PAGES] == 0) |
| { |
| psProcessStats->ui32StatAllocFlags &= ~(IMG_UINT32)(1 << (PVRSRV_PROCESS_STAT_TYPE_MAP_UMA_LMA_PAGES-PVRSRV_PROCESS_STAT_TYPE_KMALLOC)); |
| } |
| } |
| break; |
| |
| default: |
| { |
| PVR_ASSERT(0); |
| } |
| break; |
| } |
| |
| } |
| |
| #if defined(PVRSRV_ENABLE_MEMTRACK_STATS_FILE) |
| void RawProcessStatsPrintElements(void *pvFile, |
| void *pvStatPtr, |
| OS_STATS_PRINTF_FUNC *pfnOSStatsPrintf) |
| { |
| PVRSRV_PROCESS_STATS *psProcessStats; |
| |
| if (pfnOSStatsPrintf == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: pfnOSStatsPrintf not set", __func__)); |
| return; |
| } |
| |
| pfnOSStatsPrintf(pvFile, "%s,%s,%s,%s,%s,%s\n", |
| "PID", |
| "MemoryUsageKMalloc", // PVRSRV_PROCESS_STAT_TYPE_KMALLOC |
| "MemoryUsageAllocPTMemoryUMA", // PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_UMA |
| "MemoryUsageAllocPTMemoryLMA", // PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_LMA |
| "MemoryUsageAllocGPUMemLMA", // PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES |
| "MemoryUsageAllocGPUMemUMA" // PVRSRV_PROCESS_STAT_TYPE_ALLOC_UMA_PAGES |
| ); |
| |
| OSLockAcquire(g_psLinkedListLock); |
| |
| psProcessStats = g_psLiveList; |
| |
| while (psProcessStats != NULL) |
| { |
| if (psProcessStats->pid != PVR_SYS_ALLOC_PID) |
| { |
| pfnOSStatsPrintf(pvFile, "%d,%d,%d,%d,%d,%d\n", |
| psProcessStats->pid, |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_KMALLOC], |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_UMA], |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_LMA], |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES], |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ALLOC_UMA_PAGES] |
| ); |
| } |
| |
| psProcessStats = psProcessStats->psNext; |
| } |
| |
| OSLockRelease(g_psLinkedListLock); |
| } /* RawProcessStatsPrintElements */ |
| #endif |
| |
| void |
| PVRSRVStatsDecrMemKAllocStat(size_t uiBytes, |
| IMG_PID decrPID) |
| { |
| #if !defined(PVR_DISABLE_KMALLOC_MEMSTATS) |
| PVRSRV_PROCESS_STATS* psProcessStats; |
| |
| /* Don't do anything if we are not initialised or we are shutting down! */ |
| if (!bProcessStatsInitialised) |
| { |
| return; |
| } |
| |
| _decrease_global_stat(PVRSRV_MEM_ALLOC_TYPE_KMALLOC, uiBytes); |
| |
| OSLockAcquire(g_psLinkedListLock); |
| |
| psProcessStats = _FindProcessStats(decrPID); |
| |
| if (psProcessStats != NULL) |
| { |
| /* Decrement the kmalloc memory stat... */ |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_KMALLOC, uiBytes); |
| DECREASE_STAT_VALUE(psProcessStats, PVRSRV_PROCESS_STAT_TYPE_TOTAL, uiBytes); |
| } |
| |
| OSLockRelease(g_psLinkedListLock); |
| #endif |
| } |
| |
| static void |
| _StatsDecrMemTrackedStat(_PVR_STATS_TRACKING_HASH_ENTRY *psTrackingHashEntry, |
| PVRSRV_MEM_ALLOC_TYPE eAllocType) |
| { |
| PVRSRV_PROCESS_STATS* psProcessStats; |
| |
| /* Don't do anything if we are not initialised or we are shutting down! */ |
| if (!bProcessStatsInitialised) |
| { |
| return; |
| } |
| |
| _decrease_global_stat(eAllocType, psTrackingHashEntry->uiSizeInBytes); |
| |
| OSLockAcquire(g_psLinkedListLock); |
| |
| psProcessStats = _FindProcessStats(psTrackingHashEntry->uiPid); |
| |
| if (psProcessStats != NULL) |
| { |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| /* Decrement the memory stat... */ |
| _DecreaseProcStatValue(eAllocType, |
| psProcessStats, |
| psTrackingHashEntry->uiSizeInBytes); |
| OSLockRelease(psProcessStats->hLock); |
| } |
| |
| OSLockRelease(g_psLinkedListLock); |
| } |
| |
| void |
| PVRSRVStatsDecrMemAllocStatAndUntrack(PVRSRV_MEM_ALLOC_TYPE eAllocType, |
| IMG_UINT64 uiCpuVAddr) |
| { |
| _PVR_STATS_TRACKING_HASH_ENTRY *psTrackingHashEntry = NULL; |
| |
| if (!bProcessStatsInitialised || (gpsSizeTrackingHashTable == NULL)) |
| { |
| return; |
| } |
| |
| OSLockAcquire(gpsSizeTrackingHashTableLock); |
| psTrackingHashEntry = (_PVR_STATS_TRACKING_HASH_ENTRY *)HASH_Remove(gpsSizeTrackingHashTable, uiCpuVAddr); |
| OSLockRelease(gpsSizeTrackingHashTableLock); |
| if (psTrackingHashEntry) |
| { |
| _StatsDecrMemTrackedStat(psTrackingHashEntry, eAllocType); |
| OSFreeMemNoStats(psTrackingHashEntry); |
| } |
| } |
| |
| void |
| PVRSRVStatsDecrMemAllocStat(PVRSRV_MEM_ALLOC_TYPE eAllocType, |
| size_t uiBytes, |
| IMG_PID currentPid) |
| { |
| IMG_PID currentCleanupPid = PVRSRVGetPurgeConnectionPid(); |
| PVRSRV_DATA* psPVRSRVData = PVRSRVGetPVRSRVData(); |
| PVRSRV_PROCESS_STATS* psProcessStats = NULL; |
| |
| /* Don't do anything if we are not initialised or we are shutting down! */ |
| if (!bProcessStatsInitialised) |
| { |
| return; |
| } |
| |
| _decrease_global_stat(eAllocType, uiBytes); |
| |
| OSLockAcquire(g_psLinkedListLock); |
| if (psPVRSRVData) |
| { |
| if ((currentPid == psPVRSRVData->cleanupThreadPid) && |
| (currentCleanupPid != 0)) |
| { |
| psProcessStats = _FindProcessStats(currentCleanupPid); |
| } |
| else |
| { |
| psProcessStats = _FindProcessStats(currentPid); |
| } |
| } |
| else |
| { |
| psProcessStats = _FindProcessStats(currentPid); |
| } |
| |
| |
| if (psProcessStats != NULL) |
| { |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| /*Release the list lock as soon as we acquire the process lock, |
| * this ensures if the process is in deadlist the entry cannot be deleted or modified */ |
| OSLockRelease(g_psLinkedListLock); |
| /* Update the memory watermarks... */ |
| _DecreaseProcStatValue(eAllocType, |
| psProcessStats, |
| uiBytes); |
| OSLockRelease(psProcessStats->hLock); |
| |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) |
| /* If all stats are now zero, remove the entry for this thread */ |
| if (psProcessStats->ui32StatAllocFlags == 0) |
| { |
| OSLockAcquire(g_psLinkedListLock); |
| _MoveProcessToDeadList(psProcessStats); |
| OSLockRelease(g_psLinkedListLock); |
| |
| /* Check if the dead list needs to be reduced */ |
| _CompressMemoryUsage(); |
| } |
| #endif |
| }else{ |
| OSLockRelease(g_psLinkedListLock); |
| } |
| } |
| |
| /* For now we do not want to expose the global stats API |
| * so we wrap it into this specific function for pooled pages. |
| * As soon as we need to modify the global stats directly somewhere else |
| * we want to replace these functions with more general ones. |
| */ |
| void |
| PVRSRVStatsIncrMemAllocPoolStat(size_t uiBytes) |
| { |
| _increase_global_stat(PVRSRV_MEM_ALLOC_TYPE_UMA_POOL_PAGES, uiBytes); |
| } |
| |
| void |
| PVRSRVStatsDecrMemAllocPoolStat(size_t uiBytes) |
| { |
| _decrease_global_stat(PVRSRV_MEM_ALLOC_TYPE_UMA_POOL_PAGES, uiBytes); |
| } |
| |
| void |
| PVRSRVStatsUpdateRenderContextStats(IMG_UINT32 ui32TotalNumPartialRenders, |
| IMG_UINT32 ui32TotalNumOutOfMemory, |
| IMG_UINT32 ui32NumTAStores, |
| IMG_UINT32 ui32Num3DStores, |
| IMG_UINT32 ui32NumSHStores, |
| IMG_UINT32 ui32NumCDMStores, |
| IMG_PID pidOwner) |
| { |
| IMG_PID pidCurrent = pidOwner; |
| |
| PVRSRV_PROCESS_STATS* psProcessStats; |
| |
| /* Don't do anything if we are not initialised or we are shutting down! */ |
| if (!bProcessStatsInitialised) |
| { |
| return; |
| } |
| |
| /* Lock while we find the correct process and update the record... */ |
| OSLockAcquire(g_psLinkedListLock); |
| |
| psProcessStats = _FindProcessStats(pidCurrent); |
| if (psProcessStats != NULL) |
| { |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_RC_PRS] += ui32TotalNumPartialRenders; |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_RC_OOMS] += ui32TotalNumOutOfMemory; |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_RC_TA_STORES] += ui32NumTAStores; |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_RC_3D_STORES] += ui32Num3DStores; |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_RC_SH_STORES] += ui32NumSHStores; |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_RC_CDM_STORES]+= ui32NumCDMStores; |
| OSLockRelease(psProcessStats->hLock); |
| } |
| else |
| { |
| PVR_DPF((PVR_DBG_WARNING, "PVRSRVStatsUpdateRenderContextStats: Null process. Pid=%d", pidCurrent)); |
| } |
| |
| OSLockRelease(g_psLinkedListLock); |
| } /* PVRSRVStatsUpdateRenderContextStats */ |
| |
| void |
| PVRSRVStatsUpdateZSBufferStats(IMG_UINT32 ui32NumReqByApp, |
| IMG_UINT32 ui32NumReqByFW, |
| IMG_PID owner) |
| { |
| IMG_PID currentPid = (owner==0)?OSGetCurrentClientProcessIDKM():owner; |
| PVRSRV_PROCESS_STATS* psProcessStats; |
| |
| |
| /* Don't do anything if we are not initialised or we are shutting down! */ |
| if (!bProcessStatsInitialised) |
| { |
| return; |
| } |
| |
| /* Lock while we find the correct process and update the record... */ |
| OSLockAcquire(g_psLinkedListLock); |
| |
| psProcessStats = _FindProcessStats(currentPid); |
| if (psProcessStats != NULL) |
| { |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ZSBUFFER_REQS_BY_APP] += ui32NumReqByApp; |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ZSBUFFER_REQS_BY_FW] += ui32NumReqByFW; |
| OSLockRelease(psProcessStats->hLock); |
| } |
| |
| OSLockRelease(g_psLinkedListLock); |
| } /* PVRSRVStatsUpdateZSBufferStats */ |
| |
| void |
| PVRSRVStatsUpdateFreelistStats(IMG_UINT32 ui32NumGrowReqByApp, |
| IMG_UINT32 ui32NumGrowReqByFW, |
| IMG_UINT32 ui32InitFLPages, |
| IMG_UINT32 ui32NumHighPages, |
| IMG_PID ownerPid) |
| { |
| IMG_PID currentPid = (ownerPid!=0)?ownerPid:OSGetCurrentClientProcessIDKM(); |
| PVRSRV_PROCESS_STATS* psProcessStats; |
| |
| /* Don't do anything if we are not initialised or we are shutting down! */ |
| if (!bProcessStatsInitialised) |
| { |
| return; |
| } |
| |
| /* Lock while we find the correct process and update the record... */ |
| OSLockAcquire(g_psLinkedListLock); |
| |
| psProcessStats = _FindProcessStats(currentPid); |
| |
| if (psProcessStats != NULL) |
| { |
| |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_FREELIST_GROW_REQS_BY_APP] += ui32NumGrowReqByApp; |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_FREELIST_GROW_REQS_BY_FW] += ui32NumGrowReqByFW; |
| |
| UPDATE_MAX_VALUE(psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_FREELIST_PAGES_INIT], |
| (IMG_INT32) ui32InitFLPages); |
| |
| UPDATE_MAX_VALUE(psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_FREELIST_MAX_PAGES], |
| (IMG_INT32) ui32NumHighPages); |
| |
| OSLockRelease(psProcessStats->hLock); |
| |
| } |
| |
| OSLockRelease(g_psLinkedListLock); |
| } /* PVRSRVStatsUpdateFreelistStats */ |
| |
| |
| #if defined (ENABLE_DEBUGFS_PIDS) |
| |
| void |
| GenericStatsPrintElementsLive(void *pvFile, |
| void *pvStatPtr, |
| OS_STATS_PRINTF_FUNC* pfnOSStatsPrintf) |
| { |
| PVRSRV_STAT_PV_DATA *psStatType = (PVRSRV_STAT_PV_DATA *)pvStatPtr; |
| PVRSRV_PROCESS_STATS* psProcessStats; |
| |
| if (pfnOSStatsPrintf == NULL) return; |
| PVR_ASSERT(psStatType->pfnStatsPrintElements != NULL); |
| |
| pfnOSStatsPrintf(pvFile, "%s\n", psStatType->szLiveStatsHeaderStr); |
| |
| OSLockAcquire(g_psLinkedListLock); |
| |
| psProcessStats = g_psLiveList; |
| |
| if(psProcessStats == NULL) |
| { |
| pfnOSStatsPrintf(pvFile, "No Stats to display\n%s\n", g_szSeparatorStr); |
| } |
| else |
| { |
| while(psProcessStats != NULL) |
| { |
| psStatType->pfnStatsPrintElements(pvFile, psProcessStats, pfnOSStatsPrintf); |
| psProcessStats = psProcessStats->psNext; |
| pfnOSStatsPrintf(pvFile, "%s\n", g_szSeparatorStr); |
| } |
| } |
| OSLockRelease(g_psLinkedListLock); |
| } |
| |
| void |
| GenericStatsPrintElementsRetired(void *pvFile, |
| void *pvStatPtr, |
| OS_STATS_PRINTF_FUNC* pfnOSStatsPrintf) |
| { |
| PVRSRV_STAT_PV_DATA *psStatType = (PVRSRV_STAT_PV_DATA *)pvStatPtr; |
| PVRSRV_PROCESS_STATS* psProcessStats; |
| |
| if (pfnOSStatsPrintf == NULL) return; |
| PVR_ASSERT(psStatType->pfnStatsPrintElements != NULL); |
| |
| pfnOSStatsPrintf(pvFile, "%s\n", psStatType->szRetiredStatsHeaderStr); |
| |
| OSLockAcquire(g_psLinkedListLock); |
| |
| psProcessStats = g_psDeadList; |
| |
| if(psProcessStats == NULL) |
| { |
| pfnOSStatsPrintf(pvFile, "No Stats to display\n%s\n", g_szSeparatorStr); |
| } |
| else |
| { |
| while(psProcessStats != NULL) |
| { |
| psStatType->pfnStatsPrintElements(pvFile, psProcessStats, pfnOSStatsPrintf); |
| psProcessStats = psProcessStats->psNext; |
| pfnOSStatsPrintf(pvFile, "%s\n", g_szSeparatorStr); |
| } |
| } |
| OSLockRelease(g_psLinkedListLock); |
| } |
| |
| #if defined(PVRSRV_ENABLE_PERPID_STATS) |
| /*************************************************************************/ /*! |
| @Function ProcessStatsPrintElements |
| @Description Prints all elements for this process statistic record. |
| @Input pvStatPtr Pointer to statistics structure. |
| @Input pfnOSStatsPrintf Printf function to use for output. |
| */ /**************************************************************************/ |
| void |
| ProcessStatsPrintElements(void *pvFile, |
| PVRSRV_PROCESS_STATS* psProcessStats, |
| OS_STATS_PRINTF_FUNC* pfnOSStatsPrintf) |
| { |
| IMG_UINT32 ui32StatNumber; |
| |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| |
| pfnOSStatsPrintf(pvFile, "PID %u\n", psProcessStats->pid); |
| |
| /* Loop through all the values and print them... */ |
| for (ui32StatNumber = 0; |
| ui32StatNumber < ARRAY_SIZE(pszProcessStatType); |
| ui32StatNumber++) |
| { |
| if (OSStringCompare(pszProcessStatType[ui32StatNumber], "") != 0) |
| { |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) |
| if ((ui32StatNumber == PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES) || |
| (ui32StatNumber == PVRSRV_PROCESS_STAT_TYPE_ALLOC_UMA_PAGES)) |
| { |
| /* get the stat from RI */ |
| IMG_INT32 ui32Total = RITotalAllocProcessKM(psProcessStats->pid, |
| (ui32StatNumber == PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES) |
| ? PHYS_HEAP_TYPE_LMA : PHYS_HEAP_TYPE_UMA); |
| |
| pfnOSStatsPrintf(pvFile, "%-34s%10d %8dK\n", |
| pszProcessStatType[ui32StatNumber], ui32Total, ui32Total>>10); |
| } |
| else |
| #endif |
| { |
| if (ui32StatNumber >= PVRSRV_PROCESS_STAT_TYPE_KMALLOC && |
| ui32StatNumber <= PVRSRV_PROCESS_STAT_TYPE_TOTAL_MAX) |
| { |
| pfnOSStatsPrintf(pvFile, "%-34s%10d %8dK\n", |
| pszProcessStatType[ui32StatNumber], |
| psProcessStats->i32StatValue[ui32StatNumber], |
| psProcessStats->i32StatValue[ui32StatNumber] >> 10); |
| } |
| else |
| { |
| pfnOSStatsPrintf(pvFile, "%-34s%10d\n", |
| pszProcessStatType[ui32StatNumber], |
| psProcessStats->i32StatValue[ui32StatNumber]); |
| } |
| } |
| } |
| } |
| |
| OSLockRelease(psProcessStats->hLock); |
| } /* ProcessStatsPrintElements */ |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_CACHEOP_STATS) |
| void |
| PVRSRVStatsUpdateCacheOpStats(PVRSRV_CACHE_OP uiCacheOp, |
| IMG_UINT32 ui32OpSeqNum, |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) && defined(DEBUG) |
| IMG_DEV_VIRTADDR sDevVAddr, |
| IMG_DEV_PHYADDR sDevPAddr, |
| IMG_UINT32 eFenceOpType, |
| #endif |
| IMG_DEVMEM_SIZE_T uiOffset, |
| IMG_DEVMEM_SIZE_T uiSize, |
| IMG_UINT64 ui64ExecuteTime, |
| IMG_BOOL bRangeBasedFlush, |
| IMG_BOOL bUserModeFlush, |
| IMG_BOOL bIsFence, |
| IMG_PID ownerPid) |
| { |
| IMG_PID currentPid = (ownerPid!=0)?ownerPid:OSGetCurrentClientProcessIDKM(); |
| PVRSRV_PROCESS_STATS* psProcessStats; |
| |
| /* Don't do anything if we are not initialised or we are shutting down! */ |
| if (!bProcessStatsInitialised) |
| { |
| return; |
| } |
| |
| /* Lock while we find the correct process and update the record... */ |
| OSLockAcquire(g_psLinkedListLock); |
| |
| psProcessStats = _FindProcessStats(currentPid); |
| |
| if (psProcessStats != NULL) |
| { |
| IMG_INT32 Idx; |
| |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| |
| /* Look-up next buffer write index */ |
| Idx = psProcessStats->uiCacheOpWriteIndex; |
| psProcessStats->uiCacheOpWriteIndex = INCREMENT_CACHEOP_STAT_IDX_WRAP(Idx); |
| |
| /* Store all CacheOp meta-data */ |
| psProcessStats->asCacheOp[Idx].uiCacheOp = uiCacheOp; |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) && defined(DEBUG) |
| psProcessStats->asCacheOp[Idx].sDevVAddr = sDevVAddr; |
| psProcessStats->asCacheOp[Idx].sDevPAddr = sDevPAddr; |
| psProcessStats->asCacheOp[Idx].eFenceOpType = eFenceOpType; |
| #endif |
| psProcessStats->asCacheOp[Idx].uiOffset = uiOffset; |
| psProcessStats->asCacheOp[Idx].uiSize = uiSize; |
| psProcessStats->asCacheOp[Idx].bRangeBasedFlush = bRangeBasedFlush; |
| psProcessStats->asCacheOp[Idx].bUserModeFlush = bUserModeFlush; |
| psProcessStats->asCacheOp[Idx].ui64ExecuteTime = ui64ExecuteTime; |
| psProcessStats->asCacheOp[Idx].ui32OpSeqNum = ui32OpSeqNum; |
| psProcessStats->asCacheOp[Idx].bIsFence = bIsFence; |
| |
| OSLockRelease(psProcessStats->hLock); |
| } |
| |
| OSLockRelease(g_psLinkedListLock); |
| } /* PVRSRVStatsUpdateCacheOpStats */ |
| |
| /*************************************************************************/ /*! |
| @Function CacheOpStatsPrintElements |
| @Description Prints all elements for this process statistic CacheOp record. |
| @Input pvStatPtr Pointer to statistics structure. |
| @Input pfnOSStatsPrintf Printf function to use for output. |
| */ /**************************************************************************/ |
| void |
| CacheOpStatsPrintElements(void *pvFile, |
| PVRSRV_PROCESS_STATS* psProcessStats, |
| OS_STATS_PRINTF_FUNC* pfnOSStatsPrintf) |
| { |
| IMG_CHAR *pszCacheOpType, *pszFlushType, *pszFlushMode; |
| IMG_INT32 i32WriteIdx, i32ReadIdx; |
| |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) && defined(DEBUG) |
| #define CACHEOP_RI_PRINTF_HEADER \ |
| "%-10s %-10s %-5s %-16s %-16s %-10s %-10s %-12s %-12s\n" |
| #define CACHEOP_RI_PRINTF_FENCE \ |
| "%-10s %-10s %-5s %-16s %-16s %-10s %-10s %-12llu 0x%-10x\n" |
| #define CACHEOP_RI_PRINTF \ |
| "%-10s %-10s %-5s 0x%-14llx 0x%-14llx 0x%-8llx 0x%-8llx %-12llu 0x%-10x\n" |
| #else |
| #define CACHEOP_PRINTF_HEADER \ |
| "%-10s %-10s %-5s %-10s %-10s %-12s %-12s\n" |
| #define CACHEOP_PRINTF_FENCE \ |
| "%-10s %-10s %-5s %-10s %-10s %-12llu 0x%-10x\n" |
| #define CACHEOP_PRINTF \ |
| "%-10s %-10s %-5s 0x%-8llx 0x%-8llx %-12llu 0x%-10x\n" |
| #endif |
| |
| pfnOSStatsPrintf(pvFile, "PID %u\n", psProcessStats->pid); |
| |
| /* File header info */ |
| pfnOSStatsPrintf(pvFile, |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) && defined(DEBUG) |
| CACHEOP_RI_PRINTF_HEADER, |
| #else |
| CACHEOP_PRINTF_HEADER, |
| #endif |
| "CacheOp", |
| "Type", |
| "Mode", |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) && defined(DEBUG) |
| "DevVAddr", |
| "DevPAddr", |
| #endif |
| "Offset", |
| "Size", |
| "Time (us)", |
| "SeqNo"); |
| |
| /* Take a snapshot of write index, read backwards in buffer |
| and wrap round at boundary */ |
| i32WriteIdx = psProcessStats->uiCacheOpWriteIndex; |
| for (i32ReadIdx = DECREMENT_CACHEOP_STAT_IDX_WRAP(i32WriteIdx); |
| i32ReadIdx != i32WriteIdx; |
| i32ReadIdx = DECREMENT_CACHEOP_STAT_IDX_WRAP(i32ReadIdx)) |
| { |
| IMG_UINT64 ui64ExecuteTime; |
| |
| if (! psProcessStats->asCacheOp[i32ReadIdx].ui32OpSeqNum) |
| { |
| break; |
| } |
| |
| ui64ExecuteTime = psProcessStats->asCacheOp[i32ReadIdx].ui64ExecuteTime; |
| |
| if (psProcessStats->asCacheOp[i32ReadIdx].bIsFence) |
| { |
| IMG_CHAR *pszFenceType = ""; |
| pszCacheOpType = "Fence"; |
| |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) && defined(DEBUG) |
| switch (psProcessStats->asCacheOp[i32ReadIdx].eFenceOpType) |
| { |
| case RGXFWIF_DM_GP: |
| pszFenceType = "GP"; |
| break; |
| |
| case RGXFWIF_DM_TDM: |
| /* Also case RGXFWIF_DM_2D: */ |
| pszFenceType = "TDM/2D"; |
| break; |
| |
| case RGXFWIF_DM_TA: |
| pszFenceType = "TA"; |
| break; |
| |
| case RGXFWIF_DM_3D: |
| pszFenceType = "3D"; |
| break; |
| |
| case RGXFWIF_DM_CDM: |
| pszFenceType = "CDM"; |
| break; |
| |
| default: |
| PVR_ASSERT(0); |
| break; |
| } |
| #endif |
| |
| pfnOSStatsPrintf(pvFile, |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) && defined(DEBUG) |
| CACHEOP_RI_PRINTF_FENCE, |
| #else |
| CACHEOP_PRINTF_FENCE, |
| #endif |
| pszCacheOpType, |
| pszFenceType, |
| "", |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) && defined(DEBUG) |
| "", |
| "", |
| #endif |
| "", |
| "", |
| ui64ExecuteTime, |
| psProcessStats->asCacheOp[i32ReadIdx].ui32OpSeqNum); |
| } |
| else |
| { |
| if (psProcessStats->asCacheOp[i32ReadIdx].bRangeBasedFlush) |
| { |
| IMG_DEVMEM_SIZE_T ui64NumOfPages; |
| |
| ui64NumOfPages = psProcessStats->asCacheOp[i32ReadIdx].uiSize >> OSGetPageShift(); |
| if (ui64NumOfPages <= PMR_MAX_TRANSLATION_STACK_ALLOC) |
| { |
| pszFlushType = "RBF.Fast"; |
| } |
| else |
| { |
| pszFlushType = "RBF.Slow"; |
| } |
| } |
| else |
| { |
| pszFlushType = "GF"; |
| } |
| |
| if (psProcessStats->asCacheOp[i32ReadIdx].bUserModeFlush) |
| { |
| pszFlushMode = "UM"; |
| } |
| else |
| { |
| pszFlushMode = "KM"; |
| } |
| |
| switch (psProcessStats->asCacheOp[i32ReadIdx].uiCacheOp) |
| { |
| case PVRSRV_CACHE_OP_NONE: |
| pszCacheOpType = "None"; |
| break; |
| case PVRSRV_CACHE_OP_CLEAN: |
| pszCacheOpType = "Clean"; |
| break; |
| case PVRSRV_CACHE_OP_INVALIDATE: |
| pszCacheOpType = "Invalidate"; |
| break; |
| case PVRSRV_CACHE_OP_FLUSH: |
| pszCacheOpType = "Flush"; |
| break; |
| default: |
| pszCacheOpType = "Unknown"; |
| break; |
| } |
| |
| pfnOSStatsPrintf(pvFile, |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) && defined(DEBUG) |
| CACHEOP_RI_PRINTF, |
| #else |
| CACHEOP_PRINTF, |
| #endif |
| pszCacheOpType, |
| pszFlushType, |
| pszFlushMode, |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) && defined(DEBUG) |
| psProcessStats->asCacheOp[i32ReadIdx].sDevVAddr.uiAddr, |
| psProcessStats->asCacheOp[i32ReadIdx].sDevPAddr.uiAddr, |
| #endif |
| psProcessStats->asCacheOp[i32ReadIdx].uiOffset, |
| psProcessStats->asCacheOp[i32ReadIdx].uiSize, |
| ui64ExecuteTime, |
| psProcessStats->asCacheOp[i32ReadIdx].ui32OpSeqNum); |
| } |
| } |
| } /* CacheOpStatsPrintElements */ |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_MEMORY_STATS) |
| /*************************************************************************/ /*! |
| @Function MemStatsPrintElements |
| @Description Prints all elements for the memory statistic record. |
| @Input pvStatPtr Pointer to statistics structure. |
| @Input pfnOSStatsPrintf Printf function to use for output. |
| */ /**************************************************************************/ |
| void |
| MemStatsPrintElements(void *pvFile, |
| PVRSRV_PROCESS_STATS* psProcessStats, |
| OS_STATS_PRINTF_FUNC* pfnOSStatsPrintf) |
| { |
| IMG_UINT32 ui32VAddrFields = sizeof(void*)/sizeof(IMG_UINT32); |
| IMG_UINT32 ui32PAddrFields = sizeof(IMG_CPU_PHYADDR)/sizeof(IMG_UINT32); |
| PVRSRV_MEM_ALLOC_REC *psRecord; |
| IMG_UINT32 ui32ItemNumber; |
| |
| /* Write the header... */ |
| pfnOSStatsPrintf(pvFile, "PID "); |
| |
| pfnOSStatsPrintf(pvFile, "Type VAddress"); |
| for (ui32ItemNumber = 1; ui32ItemNumber < ui32VAddrFields; ui32ItemNumber++) |
| { |
| pfnOSStatsPrintf(pvFile, " "); |
| } |
| |
| pfnOSStatsPrintf(pvFile, " PAddress"); |
| for (ui32ItemNumber = 1; ui32ItemNumber < ui32PAddrFields; ui32ItemNumber++) |
| { |
| pfnOSStatsPrintf(pvFile, " "); |
| } |
| |
| pfnOSStatsPrintf(pvFile, " Size(bytes)\n"); |
| |
| psRecord = psProcessStats->psMemoryRecords; |
| if (psRecord == NULL) |
| { |
| pfnOSStatsPrintf(pvFile, "%-5d\n", psProcessStats->pid); |
| } |
| |
| while (psRecord != NULL) |
| { |
| IMG_BOOL bPrintStat = IMG_TRUE; |
| |
| pfnOSStatsPrintf(pvFile, "%-5d ", psProcessStats->pid); |
| |
| switch (psRecord->eAllocType) |
| { |
| #if !defined(PVR_DISABLE_KMALLOC_MEMSTATS) |
| case PVRSRV_MEM_ALLOC_TYPE_KMALLOC: pfnOSStatsPrintf(pvFile, "KMALLOC "); break; |
| case PVRSRV_MEM_ALLOC_TYPE_VMALLOC: pfnOSStatsPrintf(pvFile, "VMALLOC "); break; |
| #else |
| case PVRSRV_MEM_ALLOC_TYPE_KMALLOC: |
| case PVRSRV_MEM_ALLOC_TYPE_VMALLOC: bPrintStat = IMG_FALSE; break; |
| #endif |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_LMA: pfnOSStatsPrintf(pvFile, "ALLOC_PAGES_PT_LMA "); break; |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_UMA: pfnOSStatsPrintf(pvFile, "ALLOC_PAGES_PT_UMA "); break; |
| case PVRSRV_MEM_ALLOC_TYPE_IOREMAP_PT_LMA: pfnOSStatsPrintf(pvFile, "IOREMAP_PT_LMA "); break; |
| case PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA: pfnOSStatsPrintf(pvFile, "VMAP_PT_UMA "); break; |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_LMA_PAGES: pfnOSStatsPrintf(pvFile, "ALLOC_LMA_PAGES "); break; |
| case PVRSRV_MEM_ALLOC_TYPE_ALLOC_UMA_PAGES: pfnOSStatsPrintf(pvFile, "ALLOC_UMA_PAGES "); break; |
| case PVRSRV_MEM_ALLOC_TYPE_MAP_UMA_LMA_PAGES: pfnOSStatsPrintf(pvFile, "MAP_UMA_LMA_PAGES "); break; |
| default: pfnOSStatsPrintf(pvFile, "INVALID "); break; |
| } |
| |
| if (bPrintStat) |
| { |
| for (ui32ItemNumber = 0; ui32ItemNumber < ui32VAddrFields; ui32ItemNumber++) |
| { |
| pfnOSStatsPrintf(pvFile, "%08x", *(((IMG_UINT32*) &psRecord->pvCpuVAddr) + ui32VAddrFields - ui32ItemNumber - 1)); |
| } |
| pfnOSStatsPrintf(pvFile, " "); |
| |
| for (ui32ItemNumber = 0; ui32ItemNumber < ui32PAddrFields; ui32ItemNumber++) |
| { |
| pfnOSStatsPrintf(pvFile, "%08x", *(((IMG_UINT32*) &psRecord->sCpuPAddr.uiAddr) + ui32PAddrFields - ui32ItemNumber - 1)); |
| } |
| |
| #if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) && defined(DEBUG) |
| pfnOSStatsPrintf(pvFile, " %u", psRecord->uiBytes); |
| |
| pfnOSStatsPrintf(pvFile, " %s", (IMG_CHAR*)psRecord->pvAllocdFromFile); |
| |
| pfnOSStatsPrintf(pvFile, " %d\n", psRecord->ui32AllocdFromLine); |
| #else |
| pfnOSStatsPrintf(pvFile, " %u\n", psRecord->uiBytes); |
| #endif |
| } |
| /* Move to next record... */ |
| psRecord = psRecord->psNext; |
| } |
| } /* MemStatsPrintElements */ |
| #endif |
| |
| #if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) |
| /*************************************************************************/ /*! |
| @Function RIMemStatsPrintElements |
| @Description Prints all elements for the RI Memory record. |
| @Input pvStatPtr Pointer to statistics structure. |
| @Input pfnOSStatsPrintf Printf function to use for output. |
| */ /**************************************************************************/ |
| void |
| RIMemStatsPrintElements(void *pvFile, |
| PVRSRV_PROCESS_STATS* psProcessStats, |
| OS_STATS_PRINTF_FUNC* pfnOSStatsPrintf) |
| { |
| IMG_CHAR *pszStatFmtText = NULL; |
| IMG_HANDLE *pRIHandle = NULL; |
| |
| /* Acquire RI lock*/ |
| RILockAcquireKM(); |
| |
| /* |
| * Loop through the RI system to get each line of text. |
| */ |
| while (RIGetListEntryKM(psProcessStats->pid, |
| &pRIHandle, |
| &pszStatFmtText)) |
| { |
| pfnOSStatsPrintf(pvFile, "%s", pszStatFmtText); |
| } |
| |
| /* Release RI lock*/ |
| RILockReleaseKM(); |
| |
| } /* RIMemStatsPrintElements */ |
| #endif |
| |
| #endif |
| |
| static IMG_UINT32 ui32FirmwareStartTimestamp; |
| static IMG_UINT64 ui64FirmwareIdleDuration; |
| |
| void SetFirmwareStartTime(IMG_UINT32 ui32Time) |
| { |
| ui32FirmwareStartTimestamp = UPDATE_TIME(ui32FirmwareStartTimestamp, ui32Time); |
| } |
| |
| void SetFirmwareHandshakeIdleTime(IMG_UINT64 ui64Duration) |
| { |
| ui64FirmwareIdleDuration = UPDATE_TIME(ui64FirmwareIdleDuration, ui64Duration); |
| } |
| |
| static INLINE void PowerStatsPrintGroup(IMG_UINT32 *pui32Stats, |
| void *pvFile, |
| OS_STATS_PRINTF_FUNC *pfnPrintf, |
| PVRSRV_POWER_STAT_TYPE eForced, |
| PVRSRV_POWER_STAT_TYPE ePowerOn) |
| { |
| IMG_UINT32 ui32Index; |
| |
| ui32Index = GET_POWER_STAT_INDEX(eForced, ePowerOn, PRE_POWER, DEVICE); |
| pfnPrintf(pvFile, " Pre-Device: %9u\n", pui32Stats[ui32Index]); |
| |
| ui32Index = GET_POWER_STAT_INDEX(eForced, ePowerOn, PRE_POWER, SYSTEM); |
| pfnPrintf(pvFile, " Pre-System: %9u\n", pui32Stats[ui32Index]); |
| |
| ui32Index = GET_POWER_STAT_INDEX(eForced, ePowerOn, POST_POWER, SYSTEM); |
| pfnPrintf(pvFile, " Post-System: %9u\n", pui32Stats[ui32Index]); |
| |
| ui32Index = GET_POWER_STAT_INDEX(eForced, ePowerOn, POST_POWER, DEVICE); |
| pfnPrintf(pvFile, " Post-Device: %9u\n", pui32Stats[ui32Index]); |
| } |
| |
| void PowerStatsPrintElements(void *pvFile, |
| void *pvStatPtr, |
| OS_STATS_PRINTF_FUNC* pfnOSStatsPrintf) |
| { |
| IMG_UINT32 *pui32Stats = &aui32PowerTimingStats[0]; |
| IMG_UINT32 ui32Idx; |
| |
| PVR_UNREFERENCED_PARAMETER(pvStatPtr); |
| |
| if (pfnOSStatsPrintf == NULL) |
| { |
| return; |
| } |
| |
| pfnOSStatsPrintf(pvFile, "Forced Power-on Transition (nanoseconds):\n"); |
| PowerStatsPrintGroup(pui32Stats, pvFile, pfnOSStatsPrintf, FORCED, POWER_ON); |
| pfnOSStatsPrintf(pvFile, "\n"); |
| |
| pfnOSStatsPrintf(pvFile, "Forced Power-off Transition (nanoseconds):\n"); |
| PowerStatsPrintGroup(pui32Stats, pvFile, pfnOSStatsPrintf, FORCED, POWER_OFF); |
| pfnOSStatsPrintf(pvFile, "\n"); |
| |
| pfnOSStatsPrintf(pvFile, "Not Forced Power-on Transition (nanoseconds):\n"); |
| PowerStatsPrintGroup(pui32Stats, pvFile, pfnOSStatsPrintf, NOT_FORCED, POWER_ON); |
| pfnOSStatsPrintf(pvFile, "\n"); |
| |
| pfnOSStatsPrintf(pvFile, "Not Forced Power-off Transition (nanoseconds):\n"); |
| PowerStatsPrintGroup(pui32Stats, pvFile, pfnOSStatsPrintf, NOT_FORCED, POWER_OFF); |
| pfnOSStatsPrintf(pvFile, "\n"); |
| |
| |
| pfnOSStatsPrintf(pvFile, "FW bootup time (timer ticks): %u\n", ui32FirmwareStartTimestamp); |
| pfnOSStatsPrintf(pvFile, "Host Acknowledge Time for FW Idle Signal (timer ticks): %u\n", (IMG_UINT32)(ui64FirmwareIdleDuration)); |
| pfnOSStatsPrintf(pvFile, "\n"); |
| |
| pfnOSStatsPrintf(pvFile, "Last %d Clock Speed Change Timers (nanoseconds):\n", NUM_EXTRA_POWER_STATS); |
| pfnOSStatsPrintf(pvFile, "Prepare DVFS\tDVFS Change\tPost DVFS\n"); |
| |
| for (ui32Idx = ui32ClockSpeedIndexStart; ui32Idx !=ui32ClockSpeedIndexEnd; ui32Idx = (ui32Idx + 1) % NUM_EXTRA_POWER_STATS) |
| { |
| pfnOSStatsPrintf(pvFile, "%12llu\t%11llu\t%9llu\n",asClockSpeedChanges[ui32Idx].ui64PreClockSpeedChangeDuration, |
| asClockSpeedChanges[ui32Idx].ui64BetweenPreEndingAndPostStartingDuration, |
| asClockSpeedChanges[ui32Idx].ui64PostClockSpeedChangeDuration); |
| } |
| |
| |
| } /* PowerStatsPrintElements */ |
| |
| void GlobalStatsPrintElements(void *pvFile, |
| void *pvStatPtr, |
| OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf) |
| { |
| PVR_UNREFERENCED_PARAMETER(pvStatPtr); |
| |
| if (pfnOSGetStatsPrintf != NULL) |
| { |
| IMG_UINT32 ui32StatNumber; |
| |
| OSLockAcquire(gsGlobalStats.hGlobalStatsLock); |
| |
| for (ui32StatNumber = 0; |
| ui32StatNumber < ARRAY_SIZE(pszDriverStatType); |
| ui32StatNumber++) |
| { |
| if (OSStringCompare(pszDriverStatType[ui32StatNumber], "") != 0) |
| { |
| pfnOSGetStatsPrintf(pvFile, "%-34s%10d\n", |
| pszDriverStatType[ui32StatNumber], |
| GET_GLOBAL_STAT_VALUE(ui32StatNumber)); |
| } |
| } |
| |
| OSLockRelease(gsGlobalStats.hGlobalStatsLock); |
| } |
| } |
| |
| /*************************************************************************/ /*! |
| @Function PVRSRVFindProcessMemStats |
| @Description Using the provided PID find memory stats for that process. |
| Memstats will be provided for live/connected processes only. |
| Memstat values provided by this API relate only to the physical |
| memory allocated by the process and does not relate to any of |
| the mapped or imported memory. |
| @Input pid Process to search for. |
| @Input ArraySize Size of the array where memstat |
| records will be stored |
| @Input bAllProcessStats Flag to denote if stats for |
| individual process are requested |
| stats for all processes are |
| requested |
| @Input MemoryStats Handle to the memory where memstats |
| are stored. |
| @Output Memory statistics records for the requested pid. |
| */ /**************************************************************************/ |
| PVRSRV_ERROR PVRSRVFindProcessMemStats(IMG_PID pid, IMG_UINT32 ui32ArrSize, IMG_BOOL bAllProcessStats, IMG_UINT32 *pui32MemoryStats) |
| { |
| IMG_INT i; |
| PVRSRV_PROCESS_STATS* psProcessStats; |
| |
| PVR_LOGR_IF_FALSE(pui32MemoryStats != NULL, |
| "pui32MemoryStats is NULL", |
| PVRSRV_ERROR_INVALID_PARAMS); |
| |
| if (bAllProcessStats) |
| { |
| PVR_LOGR_IF_FALSE(ui32ArrSize == PVRSRV_DRIVER_STAT_TYPE_COUNT, |
| "MemStats array size is incorrect", |
| PVRSRV_ERROR_INVALID_PARAMS); |
| |
| OSLockAcquire(gsGlobalStats.hGlobalStatsLock); |
| |
| for (i = 0; i < ui32ArrSize; i++) |
| { |
| pui32MemoryStats[i] = GET_GLOBAL_STAT_VALUE(i); |
| } |
| |
| OSLockRelease(gsGlobalStats.hGlobalStatsLock); |
| |
| return PVRSRV_OK; |
| } |
| |
| PVR_LOGR_IF_FALSE(ui32ArrSize == PVRSRV_PROCESS_STAT_TYPE_COUNT, |
| "MemStats array size is incorrect", |
| PVRSRV_ERROR_INVALID_PARAMS); |
| |
| OSLockAcquire(g_psLinkedListLock); |
| |
| /* Search for the given PID in the Live List */ |
| psProcessStats = _FindProcessStatsInLiveList(pid); |
| |
| if (psProcessStats == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "Process %d not found. This process may not be live anymore.", (IMG_INT)pid)); |
| OSLockRelease(g_psLinkedListLock); |
| |
| return PVRSRV_ERROR_PROCESS_NOT_FOUND; |
| } |
| |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| for (i = 0; i < ui32ArrSize; i++) |
| { |
| pui32MemoryStats[i] = psProcessStats->i32StatValue[i]; |
| } |
| OSLockRelease(psProcessStats->hLock); |
| |
| OSLockRelease(g_psLinkedListLock); |
| |
| return PVRSRV_OK; |
| |
| } /* PVRSRVFindProcessMemStats */ |
| |
| /*************************************************************************/ /*! |
| @Function PVRSRVGetProcessMemUsage |
| @Description Calculate allocated kernel and graphics memory for all live/connected processes. |
| Memstat values provided by this API relate only to the physical |
| memory allocated by the process and does not relate to any of |
| the mapped or imported memory. |
| @Output pui32TotalMem Total memory usage for all live PIDs connected to the driver. |
| @Output pui32NumberOfLivePids Number of live pids currently connected to the server. |
| @Output ppsPerProcessMemUsageData Handle to an array of PVRSRV_PER_PROCESS_MEM_USAGE, number of elements defined by pui32NumberOfLivePids. |
| @Return PVRSRV_OK Success |
| PVRSRV_ERROR_PROCESS_NOT_FOUND No live processes. |
| PVRSRV_ERROR_OUT_OF_MEMORY Failed to allocate memory for ppsPerProcessMemUsageData. |
| */ /**************************************************************************/ |
| PVRSRV_ERROR PVRSRVGetProcessMemUsage(IMG_UINT32 *pui32TotalMem, |
| IMG_UINT32 *pui32NumberOfLivePids, |
| PVRSRV_PER_PROCESS_MEM_USAGE **ppsPerProcessMemUsageData) |
| { |
| IMG_UINT32 ui32Counter = 0; |
| IMG_UINT32 ui32NumberOfLivePids = 0; |
| PVRSRV_ERROR eError = PVRSRV_ERROR_PROCESS_NOT_FOUND; |
| PVRSRV_PROCESS_STATS* psProcessStats = NULL; |
| PVRSRV_PER_PROCESS_MEM_USAGE* psPerProcessMemUsageData = NULL; |
| |
| OSLockAcquire(gsGlobalStats.hGlobalStatsLock); |
| |
| *pui32TotalMem = GET_GLOBAL_STAT_VALUE(PVRSRV_DRIVER_STAT_TYPE_KMALLOC) + |
| GET_GLOBAL_STAT_VALUE(PVRSRV_DRIVER_STAT_TYPE_VMALLOC) + |
| GET_GLOBAL_STAT_VALUE(PVRSRV_DRIVER_STAT_TYPE_ALLOC_GPUMEM_LMA) + |
| GET_GLOBAL_STAT_VALUE(PVRSRV_DRIVER_STAT_TYPE_ALLOC_GPUMEM_UMA) + |
| GET_GLOBAL_STAT_VALUE(PVRSRV_DRIVER_STAT_TYPE_ALLOC_PT_MEMORY_UMA) + |
| GET_GLOBAL_STAT_VALUE(PVRSRV_DRIVER_STAT_TYPE_ALLOC_PT_MEMORY_LMA); |
| |
| OSLockRelease(gsGlobalStats.hGlobalStatsLock); |
| |
| OSLockAcquire(g_psLinkedListLock); |
| psProcessStats = g_psLiveList; |
| |
| while (psProcessStats != NULL) |
| { |
| psProcessStats = psProcessStats->psNext; |
| ui32NumberOfLivePids++; |
| } |
| |
| if (ui32NumberOfLivePids > 0) |
| { |
| /* Use OSAllocZMemNoStats to prevent deadlock. */ |
| psPerProcessMemUsageData = OSAllocZMemNoStats(ui32NumberOfLivePids * sizeof(*psPerProcessMemUsageData)); |
| |
| if (psPerProcessMemUsageData) |
| { |
| psProcessStats = g_psLiveList; |
| |
| while (psProcessStats != NULL) |
| { |
| OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT); |
| |
| psPerProcessMemUsageData[ui32Counter].ui32Pid = (IMG_UINT32)psProcessStats->pid; |
| |
| psPerProcessMemUsageData[ui32Counter].ui32KernelMemUsage = psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_KMALLOC] + |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_VMALLOC]; |
| |
| psPerProcessMemUsageData[ui32Counter].ui32GraphicsMemUsage = psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_UMA] + |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_LMA] + |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES] + |
| psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_ALLOC_UMA_PAGES]; |
| |
| OSLockRelease(psProcessStats->hLock); |
| psProcessStats = psProcessStats->psNext; |
| ui32Counter++; |
| } |
| eError = PVRSRV_OK; |
| } |
| else |
| { |
| eError = PVRSRV_ERROR_OUT_OF_MEMORY; |
| } |
| } |
| |
| OSLockRelease(g_psLinkedListLock); |
| *pui32NumberOfLivePids = ui32NumberOfLivePids; |
| *ppsPerProcessMemUsageData = psPerProcessMemUsageData; |
| |
| return eError; |
| |
| } /* PVRSRVGetProcessMemUsage */ |