blob: 67358bee1e1d445fb9afc6a90ee1ffbbe7e8f082 [file] [log] [blame]
/*************************************************************************/ /*!
@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 <stddef.h>
#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"
#if defined(DEBUG) || defined(PVRSRV_ENABLE_PROCESS_STATS_DEBUGFS) || \
defined(PVRSRV_ENABLE_MEMORY_STATS) || \
(defined(PVR_RI_DEBUG) && defined(PVR_RI_DEBUG_DEBUGFS))
#define ENABLE_DEBUGFS
#endif
/*
* Maximum history of process statistics that will be kept.
*/
#define MAX_DEAD_LIST_PROCESSES (10)
/*
* Definition of all process based statistics and the strings used to
* format them.
*/
typedef enum
{
/* Stats that are per process... */
PVRSRV_PROCESS_STAT_TYPE_CONNECTIONS,
PVRSRV_PROCESS_STAT_TYPE_MAX_CONNECTIONS,
PVRSRV_PROCESS_STAT_TYPE_RC_OOMS,
PVRSRV_PROCESS_STAT_TYPE_RC_PRS,
PVRSRV_PROCESS_STAT_TYPE_RC_GROWS,
PVRSRV_PROCESS_STAT_TYPE_RC_PUSH_GROWS,
PVRSRV_PROCESS_STAT_TYPE_RC_TA_STORES,
PVRSRV_PROCESS_STAT_TYPE_RC_3D_STORES,
PVRSRV_PROCESS_STAT_TYPE_RC_SH_STORES,
PVRSRV_PROCESS_STAT_TYPE_RC_CDM_STORES,
PVRSRV_PROCESS_STAT_TYPE_ZSBUFFER_REQS_BY_APP,
PVRSRV_PROCESS_STAT_TYPE_ZSBUFFER_REQS_BY_FW,
PVRSRV_PROCESS_STAT_TYPE_FREELIST_GROW_REQS_BY_APP,
PVRSRV_PROCESS_STAT_TYPE_FREELIST_GROW_REQS_BY_FW,
PVRSRV_PROCESS_STAT_TYPE_FREELIST_PAGES_INIT,
PVRSRV_PROCESS_STAT_TYPE_FREELIST_MAX_PAGES,
PVRSRV_PROCESS_STAT_TYPE_KMALLOC,
PVRSRV_PROCESS_STAT_TYPE_KMALLOC_MAX,
PVRSRV_PROCESS_STAT_TYPE_VMALLOC,
PVRSRV_PROCESS_STAT_TYPE_VMALLOC_MAX,
PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_UMA,
PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_UMA_MAX,
PVRSRV_PROCESS_STAT_TYPE_VMAP_PT_UMA,
PVRSRV_PROCESS_STAT_TYPE_VMAP_PT_UMA_MAX,
PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_LMA,
PVRSRV_PROCESS_STAT_TYPE_ALLOC_PAGES_PT_LMA_MAX,
PVRSRV_PROCESS_STAT_TYPE_IOREMAP_PT_LMA,
PVRSRV_PROCESS_STAT_TYPE_IOREMAP_PT_LMA_MAX,
PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES,
PVRSRV_PROCESS_STAT_TYPE_ALLOC_LMA_PAGES_MAX,
PVRSRV_PROCESS_STAT_TYPE_ALLOC_UMA_PAGES,
PVRSRV_PROCESS_STAT_TYPE_ALLOC_UMA_PAGES_MAX,
PVRSRV_PROCESS_STAT_TYPE_MAP_UMA_LMA_PAGES,
PVRSRV_PROCESS_STAT_TYPE_MAP_UMA_LMA_PAGES_MAX,
/* Must be the last enum...*/
PVRSRV_PROCESS_STAT_TYPE_COUNT
} PVRSRV_PROCESS_STAT_TYPE;
static const IMG_CHAR *const pszProcessStatFmt[PVRSRV_PROCESS_STAT_TYPE_COUNT] = {
"Connections %10d\n", /* PVRSRV_STAT_TYPE_CONNECTIONS */
"ConnectionsMax %10d\n", /* PVRSRV_STAT_TYPE_MAXCONNECTIONS */
"RenderContextOutOfMemoryEvents %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_RC_OOMS */
"RenderContextPartialRenders %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_RC_PRS */
"RenderContextGrows %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_RC_GROWS */
"RenderContextPushGrows %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_RC_PUSH_GROWS */
"RenderContextTAStores %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_RC_TA_STORES */
"RenderContext3DStores %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_RC_3D_STORES */
"RenderContextSHStores %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_RC_SH_STORES */
"RenderContextCDMStores %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_RC_CDM_STORES */
"ZSBufferRequestsByApp %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_ZSBUFFER_REQS_BY_APP */
"ZSBufferRequestsByFirmware %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_ZSBUFFER_REQS_BY_FW */
"FreeListGrowRequestsByApp %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_FREELIST_GROW_REQS_BY_APP */
"FreeListGrowRequestsByFirmware %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_FREELIST_GROW_REQS_BY_FW */
"FreeListInitialPages %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_FREELIST_PAGES_INIT */
"FreeListMaxPages %10d\n", /* PVRSRV_PROCESS_STAT_TYPE_FREELIST_MAX_PAGES */
#if !defined(PVR_DISABLE_KMALLOC_MEMSTATS)
"MemoryUsageKMalloc %10d\n", /* PVRSRV_STAT_TYPE_KMALLOC */
"MemoryUsageKMallocMax %10d\n", /* PVRSRV_STAT_TYPE_MAX_KMALLOC */
"MemoryUsageVMalloc %10d\n", /* PVRSRV_STAT_TYPE_VMALLOC */
"MemoryUsageVMallocMax %10d\n", /* PVRSRV_STAT_TYPE_MAX_VMALLOC */
#else
"","","","", /* Empty strings if these stats are not logged */
#endif
"MemoryUsageAllocPTMemoryUMA %10d\n", /* PVRSRV_STAT_TYPE_ALLOC_PAGES_PT_UMA */
"MemoryUsageAllocPTMemoryUMAMax %10d\n", /* PVRSRV_STAT_TYPE_MAX_ALLOC_PAGES_PT_UMA */
"MemoryUsageVMapPTUMA %10d\n", /* PVRSRV_STAT_TYPE_VMAP_PT_UMA */
"MemoryUsageVMapPTUMAMax %10d\n", /* PVRSRV_STAT_TYPE_MAX_VMAP_PT_UMA */
"MemoryUsageAllocPTMemoryLMA %10d\n", /* PVRSRV_STAT_TYPE_ALLOC_PAGES_PT_LMA */
"MemoryUsageAllocPTMemoryLMAMax %10d\n", /* PVRSRV_STAT_TYPE_MAX_ALLOC_PAGES_PT_LMA */
"MemoryUsageIORemapPTLMA %10d\n", /* PVRSRV_STAT_TYPE_IOREMAP_PT_LMA */
"MemoryUsageIORemapPTLMAMax %10d\n", /* PVRSRV_STAT_TYPE_MAX_IOREMAP_PT_LMA */
"MemoryUsageAllocGPUMemLMA %10d\n", /* PVRSRV_STAT_TYPE_ALLOC_LMA_PAGES */
"MemoryUsageAllocGPUMemLMAMax %10d\n", /* PVRSRV_STAT_TYPE_MAX_ALLOC_LMA_PAGES */
"MemoryUsageAllocGPUMemUMA %10d\n", /* PVRSRV_STAT_TYPE_ALLOC_UMA_PAGES */
"MemoryUsageAllocGPUMemUMAMax %10d\n", /* PVRSRV_STAT_TYPE_MAX_ALLOC_UMA_PAGES */
"MemoryUsageMappedGPUMemUMA/LMA %10d\n", /* PVRSRV_STAT_TYPE_MAP_UMA_LMA_PAGES */
"MemoryUsageMappedGPUMemUMA/LMAMax %10d\n", /* PVRSRV_STAT_TYPE_MAX_MAP_UMA_LMA_PAGES */
};
/* 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);
/*
* Functions for printing the information stored...
*/
#if defined(PVRSRV_ENABLE_PROCESS_STATS_DEBUGFS)
void ProcessStatsPrintElements(void *pvFile,
void *pvStatPtr,
OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf);
#endif
#if defined(PVRSRV_ENABLE_MEMTRACK_STATS_FILE)
void RawProcessStatsPrintElements(void *pvFile,
void *pvStatPtr,
OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf);
#endif
void MemStatsPrintElements(void *pvFile,
void *pvStatPtr,
OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf);
void RIMemStatsPrintElements(void *pvFile,
void *pvStatPtr,
OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf);
void PowerStatsPrintElements(void *pvFile,
void *pvStatPtr,
OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf);
void GlobalStatsPrintElements(void *pvFile,
void *pvStatPtr,
OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf);
void CacheOpStatsPrintElements(void *pvFile,
void *pvStatPtr,
OS_STATS_PRINTF_FUNC* pfnOSGetStatsPrintf);
#if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS)
static void StripBadChars( IMG_CHAR *psStr);
#endif
/*
* 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,val) do { (var) += (val); if ((var) > (var##Max)) {(var##Max) = (var);} } 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,val) do { (var) -= (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,val) do { if ((var) >= (val)) { (var) -= (val); } else { (var) = 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...
*/
typedef enum
{
PVRSRV_STAT_STRUCTURE_PROCESS = 1,
PVRSRV_STAT_STRUCTURE_RENDER_CONTEXT = 2,
PVRSRV_STAT_STRUCTURE_MEMORY = 3,
PVRSRV_STAT_STRUCTURE_RIMEMORY = 4,
PVRSRV_STAT_STRUCTURE_CACHEOP = 5
} PVRSRV_STAT_STRUCTURE_TYPE;
#define MAX_PROC_NAME_LENGTH (32)
typedef struct _PVRSRV_PROCESS_STATS_ {
/* Structure type (must be first!) */
PVRSRV_STAT_STRUCTURE_TYPE eStructureType;
/* 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;
IMG_UINT32 ui32MemRefCount;
/* Folder name used to store the statistic */
IMG_CHAR szFolderName[MAX_PROC_NAME_LENGTH];
#if defined(ENABLE_DEBUGFS)
/* OS specific data */
void *pvOSPidFolderData;
#endif
#if defined(PVRSRV_ENABLE_PROCESS_STATS_DEBUGFS)
void *pvOSPidEntryData;
#endif
/* Stats... */
IMG_INT32 i32StatValue[PVRSRV_PROCESS_STAT_TYPE_COUNT];
IMG_UINT32 ui32StatAllocFlags;
#if defined(DEBUG)
struct _CACHEOP_STRUCT_ {
PVRSRV_CACHE_OP uiCacheOp;
#if defined(PVR_RI_DEBUG)
IMG_DEV_VIRTADDR sDevVAddr;
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 bHasTimeline;
IMG_BOOL bIsFence;
IMG_PID ownerPid;
} asCacheOp[MAX_CACHEOP_STAT];
IMG_INT32 uiCacheOpWriteIndex;
struct _PVRSRV_CACHEOP_STATS_* psCacheOpStats;
#endif
/* Other statistics structures */
struct _PVRSRV_MEMORY_STATS_* psMemoryStats;
struct _PVRSRV_RI_MEMORY_STATS_* psRIMemoryStats;
} PVRSRV_PROCESS_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;
typedef struct _PVRSRV_MEMORY_STATS_ {
/* Structure type (must be first!) */
PVRSRV_STAT_STRUCTURE_TYPE eStructureType;
/* OS specific data */
void *pvOSMemEntryData;
/* Stats... */
PVRSRV_MEM_ALLOC_REC *psMemoryRecords;
} PVRSRV_MEMORY_STATS;
typedef struct _PVRSRV_RI_MEMORY_STATS_ {
/* Structure type (must be first!) */
PVRSRV_STAT_STRUCTURE_TYPE eStructureType;
/* OS level process ID */
IMG_PID pid;
#if defined(PVR_RI_DEBUG_DEBUGFS)
/* OS specific data */
void *pvOSRIMemEntryData;
#endif
} PVRSRV_RI_MEMORY_STATS;
typedef struct _PVRSRV_CACHEOP_STATS_ {
/* Structure type (must be first!) */
PVRSRV_STAT_STRUCTURE_TYPE eStructureType;
/* OS specific data */
void *pvOSCacheOpEntryData;
} PVRSRV_CACHEOP_STATS;
#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 = NULL;
static PVRSRV_PROCESS_STATS* g_psDeadList = NULL;
static POS_LOCK g_psLinkedListLock = NULL;
/* 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)
/*
* Pointer to OS folder to hold PID folders.
*/
static IMG_CHAR *pszOSLivePidFolderName = "pid";
static IMG_CHAR *pszOSDeadPidFolderName = "pids_retired";
static void *pvOSLivePidFolder = NULL;
static void *pvOSDeadPidFolder = NULL;
#endif
#if defined(PVRSRV_ENABLE_MEMTRACK_STATS_FILE)
static void *pvOSProcStats = NULL;
#endif
/* global driver-data folders */
typedef struct _GLOBAL_STATS_
{
IMG_UINT32 ui32MemoryUsageKMalloc;
IMG_UINT32 ui32MemoryUsageKMallocMax;
IMG_UINT32 ui32MemoryUsageVMalloc;
IMG_UINT32 ui32MemoryUsageVMallocMax;
IMG_UINT32 ui32MemoryUsageAllocPTMemoryUMA;
IMG_UINT32 ui32MemoryUsageAllocPTMemoryUMAMax;
IMG_UINT32 ui32MemoryUsageVMapPTUMA;
IMG_UINT32 ui32MemoryUsageVMapPTUMAMax;
IMG_UINT32 ui32MemoryUsageAllocPTMemoryLMA;
IMG_UINT32 ui32MemoryUsageAllocPTMemoryLMAMax;
IMG_UINT32 ui32MemoryUsageIORemapPTLMA;
IMG_UINT32 ui32MemoryUsageIORemapPTLMAMax;
IMG_UINT32 ui32MemoryUsageAllocGPUMemLMA;
IMG_UINT32 ui32MemoryUsageAllocGPUMemLMAMax;
IMG_UINT32 ui32MemoryUsageAllocGPUMemUMA;
IMG_UINT32 ui32MemoryUsageAllocGPUMemUMAMax;
IMG_UINT32 ui32MemoryUsageAllocGPUMemUMAPool;
IMG_UINT32 ui32MemoryUsageAllocGPUMemUMAPoolMax;
IMG_UINT32 ui32MemoryUsageMappedGPUMemUMA_LMA;
IMG_UINT32 ui32MemoryUsageMappedGPUMemUMA_LMAMax;
POS_LOCK hGlobalStatsLock;
} GLOBAL_STATS;
static void *pvOSGlobalMemEntryRef = NULL;
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 void _AddProcessStatsToFrontOfDeadList(PVRSRV_PROCESS_STATS* psProcessStats);
static void _AddProcessStatsToFrontOfLiveList(PVRSRV_PROCESS_STATS* psProcessStats);
#if defined(PVRSRV_ENABLE_PROCESS_STATS_DEBUGFS)
static IMG_UINT32 _PVRSRVIncrMemStatRefCount(void *pvStatPtr);
static IMG_UINT32 _PVRSRVDecrMemStatRefCount(void *pvStatPtr);
#endif
#if defined(PVRSRV_ENABLE_PROCESS_STATS_DEBUGFS) || !defined(ENABLE_DEBUGFS)
static void _DestroyProcessStat(PVRSRV_PROCESS_STATS* psProcessStats);
#endif
static void _RemoveProcessStatsFromList(PVRSRV_PROCESS_STATS* psProcessStats);
#if defined(ENABLE_DEBUGFS)
static void _RemoveOSStatisticEntries(PVRSRV_PROCESS_STATS* psProcessStats);
static void _CreateOSStatisticEntries(PVRSRV_PROCESS_STATS* psProcessStats, void *pvOSPidFolder);
#endif
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 = NULL;
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;
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);
}
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 = 0, ui32ClockSpeedIndexEnd = 0;
static IMG_UINT64 ui64PreClockSpeedChangeMark = 0;
void InsertPowerTimeStatisticExtraPre(IMG_UINT64 ui64StartTimer, IMG_UINT64 ui64Stoptimer)
{
asClockSpeedChanges[ui32ClockSpeedIndexEnd].ui64PreClockSpeedChangeDuration = ui64Stoptimer - ui64StartTimer;
ui64PreClockSpeedChangeMark = OSClockus();
return ;
}
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;
return;
}
/*************************************************************************/ /*!
@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;
#if defined(ENABLE_DEBUGFS)
_RemoveOSStatisticEntries(psProcessStatsToBeFreed);
#else
_DestroyProcessStat(psProcessStatsToBeFreed);
#endif
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(ENABLE_DEBUGFS)
static void
_MoveProcessToDeadListDebugFS(PVRSRV_PROCESS_STATS* psProcessStats)
{
/* Transfer the OS entries to the folder for dead processes... */
_RemoveOSStatisticEntries(psProcessStats);
_CreateOSStatisticEntries(psProcessStats, pvOSDeadPidFolder);
} /* _MoveProcessToDeadListDebugFS */
#endif
/* 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 */
#if defined(ENABLE_DEBUGFS)
static void
_MoveProcessToLiveListDebugFS(PVRSRV_PROCESS_STATS* psProcessStats)
{
/* Transfer the OS entries to the folder for live processes... */
_RemoveOSStatisticEntries(psProcessStats);
_CreateOSStatisticEntries(psProcessStats, pvOSLivePidFolder);
} /* _MoveProcessToLiveListDebugFS */
#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 */
#if defined(ENABLE_DEBUGFS)
/*************************************************************************/ /*!
@Function _CreateOSStatisticEntries
@Description Create all OS entries for this statistic.
@Input psProcessStats Process stats to destroy.
@Input pvOSPidFolder Pointer to OS folder to place the entries in.
*/ /**************************************************************************/
static void
_CreateOSStatisticEntries(PVRSRV_PROCESS_STATS* psProcessStats,
void *pvOSPidFolder)
{
void *pvOSPidFolderData;
#if defined(PVRSRV_ENABLE_PROCESS_STATS_DEBUGFS)
void *pvOSPidEntryData;
#endif
#if defined(PVRSRV_ENABLE_MEMORY_STATS)
void *pvOSMemEntryData;
#endif
#if defined(PVR_RI_DEBUG_DEBUGFS)
void *pvOSRIMemEntryData;
#endif
#if defined(DEBUG)
void *pvOSCacheOpEntryData;
#endif
PVR_ASSERT(psProcessStats != NULL);
pvOSPidFolderData = OSCreateStatisticFolder(psProcessStats->szFolderName, pvOSPidFolder);
#if defined(PVRSRV_ENABLE_PROCESS_STATS_DEBUGFS)
pvOSPidEntryData = OSCreateStatisticEntry("process_stats",
pvOSPidFolderData,
ProcessStatsPrintElements,
_PVRSRVIncrMemStatRefCount,
_PVRSRVDecrMemStatRefCount,
(void *) psProcessStats);
#endif
#if defined(PVRSRV_ENABLE_MEMORY_STATS)
pvOSMemEntryData = OSCreateStatisticEntry("mem_area",
pvOSPidFolderData,
MemStatsPrintElements,
NULL,
NULL,
(void *) psProcessStats->psMemoryStats);
#endif
#if defined(PVR_RI_DEBUG_DEBUGFS)
pvOSRIMemEntryData = OSCreateStatisticEntry("ri_mem_area",
pvOSPidFolderData,
RIMemStatsPrintElements,
NULL,
NULL,
(void *) psProcessStats->psRIMemoryStats);
#endif
#if defined(DEBUG)
pvOSCacheOpEntryData = OSCreateStatisticEntry("cache_ops_exec",
pvOSPidFolderData,
CacheOpStatsPrintElements,
NULL,
NULL,
(void *) psProcessStats);
#endif
OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT);
psProcessStats->pvOSPidFolderData = pvOSPidFolderData;
#if defined(PVRSRV_ENABLE_PROCESS_STATS_DEBUGFS)
psProcessStats->pvOSPidEntryData = pvOSPidEntryData;
#endif
#if defined(PVRSRV_ENABLE_MEMORY_STATS)
psProcessStats->psMemoryStats->pvOSMemEntryData = pvOSMemEntryData;
#endif
#if defined(PVR_RI_DEBUG_DEBUGFS)
psProcessStats->psRIMemoryStats->pvOSRIMemEntryData = pvOSRIMemEntryData;
#endif
#if defined(DEBUG)
psProcessStats->psCacheOpStats->pvOSCacheOpEntryData = pvOSCacheOpEntryData;
#endif
OSLockRelease(psProcessStats->hLock);
} /* _CreateOSStatisticEntries */
/*************************************************************************/ /*!
@Function _RemoveOSStatisticEntries
@Description Removed all OS entries used by this statistic.
@Input psProcessStats Process stats to destroy.
*/ /**************************************************************************/
static void
_RemoveOSStatisticEntries(PVRSRV_PROCESS_STATS* psProcessStats)
{
PVR_ASSERT(psProcessStats != NULL);
#if defined(DEBUG)
OSRemoveStatisticEntry(psProcessStats->psCacheOpStats->pvOSCacheOpEntryData);
#endif
#if defined(PVR_RI_DEBUG_DEBUGFS)
OSRemoveStatisticEntry(psProcessStats->psRIMemoryStats->pvOSRIMemEntryData);
#endif
#if defined(PVRSRV_ENABLE_MEMORY_STATS)
OSRemoveStatisticEntry(psProcessStats->psMemoryStats->pvOSMemEntryData);
#endif
#if defined(PVRSRV_ENABLE_PROCESS_STATS_DEBUGFS)
if( psProcessStats->pvOSPidEntryData != NULL)
{
OSRemoveStatisticEntry(psProcessStats->pvOSPidEntryData);
}
#endif
if( psProcessStats->pvOSPidFolderData != NULL)
{
OSRemoveStatisticFolder(&psProcessStats->pvOSPidFolderData);
}
} /* _RemoveOSStatisticEntries */
#endif /* defined(ENABLE_DEBUGFS) */
#if defined(PVRSRV_ENABLE_PROCESS_STATS_DEBUGFS) || !defined(ENABLE_DEBUGFS)
/*************************************************************************/ /*!
@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->psMemoryStats->psMemoryRecords)
{
List_PVRSRV_MEM_ALLOC_REC_Remove(psProcessStats->psMemoryStats->psMemoryRecords);
}
OSFreeMemNoStats(psProcessStats->psMemoryStats);
#endif
#if defined(PVR_RI_DEBUG)
OSFreeMemNoStats(psProcessStats->psRIMemoryStats);
#endif
OSLockRelease(psProcessStats->hLock);
/*Destroy the lock */
OSLockDestroyNoStats(psProcessStats->hLock);
/* Free the memory... */
OSFreeMemNoStats(psProcessStats);
} /* _DestroyProcessStat */
#endif
#if defined(PVRSRV_ENABLE_PROCESS_STATS_DEBUGFS)
static IMG_UINT32 _PVRSRVIncrMemStatRefCount(void *pvStatPtr)
{
PVRSRV_STAT_STRUCTURE_TYPE* peStructureType = (PVRSRV_STAT_STRUCTURE_TYPE*) pvStatPtr;
PVRSRV_PROCESS_STATS* psProcessStats = (PVRSRV_PROCESS_STATS*) pvStatPtr;
IMG_UINT32 ui32Res = 0;
switch (*peStructureType)
{
case PVRSRV_STAT_STRUCTURE_PROCESS:
{
OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT);
ui32Res = ++psProcessStats->ui32MemRefCount;
OSLockRelease(psProcessStats->hLock);
break;
}
default:
{
/* _PVRSRVIncrMemStatRefCount was passed a pointer to an unrecognised struct */
PVR_ASSERT(0);
break;
}
}
return ui32Res;
}
static IMG_UINT32 _PVRSRVDecrMemStatRefCount(void *pvStatPtr)
{
PVRSRV_STAT_STRUCTURE_TYPE* peStructureType = (PVRSRV_STAT_STRUCTURE_TYPE*) pvStatPtr;
PVRSRV_PROCESS_STATS* psProcessStats = (PVRSRV_PROCESS_STATS*) pvStatPtr;
IMG_UINT32 ui32Res = 0;
switch (*peStructureType)
{
case PVRSRV_STAT_STRUCTURE_PROCESS:
{
OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT);
/* Decrement stat memory refCount and free if now zero */
ui32Res = --psProcessStats->ui32MemRefCount;
OSLockRelease(psProcessStats->hLock);
if (ui32Res == 0)
{
_DestroyProcessStat(psProcessStats);
}
break;
}
default:
{
/* _PVRSRVDecrMemStatRefCount was passed a pointer to an unrecognised struct */
PVR_ASSERT(0);
break;
}
}
return ui32Res;
}
#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, LOCK_TYPE_NONE);
if (error == PVRSRV_OK)
{
/* We also need a lock to protect the hash table used for size tracking.. */
error = OSLockCreate(&gpsSizeTrackingHashTableLock, LOCK_TYPE_NONE);
if (error != PVRSRV_OK)
{
goto e0;
}
/* We also need a lock to protect the GlobalStat counters */
error = OSLockCreate(&gsGlobalStats.hGlobalStatsLock, LOCK_TYPE_NONE);
if (error != PVRSRV_OK)
{
goto e1;
}
#if defined(ENABLE_DEBUGFS)
/* Create a pid folders for putting the PID files in... */
pvOSLivePidFolder = OSCreateStatisticFolder(pszOSLivePidFolderName, NULL);
pvOSDeadPidFolder = OSCreateStatisticFolder(pszOSDeadPidFolderName, NULL);
#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,
NULL,
NULL);
pvOSGlobalMemEntryRef = OSCreateStatisticEntry(pszDriverStatFilename,
NULL,
GlobalStatsPrintElements,
NULL,
NULL,
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;
}
return error;
e1:
OSLockDestroy(gpsSizeTrackingHashTableLock);
gpsSizeTrackingHashTableLock = NULL;
e0:
OSLockDestroy(g_psLinkedListLock);
g_psLinkedListLock = NULL;
return error;
} /* PVRSRVStatsInitialise */
/*************************************************************************/ /*!
@Function PVRSRVStatsDestroy
@Description Method for destroying the statistics module data.
*/ /**************************************************************************/
void
PVRSRVStatsDestroy(void)
{
PVR_ASSERT(bProcessStatsInitialised == IMG_TRUE);
/* Stop monitoring memory allocations... */
bProcessStatsInitialised = IMG_FALSE;
#if defined(PVRSRV_ENABLE_MEMTRACK_STATS_FILE)
if (pvOSProcStats)
{
OSRemoveRawStatisticEntry(pvOSProcStats);
pvOSProcStats = NULL;
}
#endif
/* Destroy the power stats entry... */
if (pvOSPowerStatsEntryData!=NULL)
{
OSRemoveStatisticEntry(pvOSPowerStatsEntryData);
pvOSPowerStatsEntryData=NULL;
}
/* Destroy the global data entry */
if (pvOSGlobalMemEntryRef!=NULL)
{
OSRemoveStatisticEntry(pvOSGlobalMemEntryRef);
pvOSGlobalMemEntryRef=NULL;
}
/* 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);
#if defined(ENABLE_DEBUGFS)
_RemoveOSStatisticEntries(psProcessStats);
#else
_DestroyProcessStat(psProcessStats);
#endif
}
while (g_psDeadList != NULL)
{
PVRSRV_PROCESS_STATS* psProcessStats = g_psDeadList;
_RemoveProcessStatsFromList(psProcessStats);
#if defined(ENABLE_DEBUGFS)
_RemoveOSStatisticEntries(psProcessStats);
#else
_DestroyProcessStat(psProcessStats);
#endif
}
#if defined(ENABLE_DEBUGFS)
/* Remove the OS folders used by the PID folders...
* OSRemoveStatisticFolder will NULL the pointers */
OSRemoveStatisticFolder(&pvOSLivePidFolder);
OSRemoveStatisticFolder(&pvOSDeadPidFolder);
#endif
if (gpsSizeTrackingHashTable != NULL)
{
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.ui32MemoryUsageKMalloc, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_VMALLOC:
DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageVMalloc, 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.ui32MemoryUsageAllocPTMemoryUMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA:
DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageVMapPTUMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_LMA:
DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageAllocPTMemoryLMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_IOREMAP_PT_LMA:
DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageIORemapPTLMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_ALLOC_LMA_PAGES:
DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageAllocGPUMemLMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_ALLOC_UMA_PAGES:
DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageAllocGPUMemUMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_MAP_UMA_LMA_PAGES:
DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageMappedGPUMemUMA_LMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_UMA_POOL_PAGES:
DECREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageAllocGPUMemUMAPool, 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.ui32MemoryUsageKMalloc, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_VMALLOC:
INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageVMalloc, 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.ui32MemoryUsageAllocPTMemoryUMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA:
INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageVMapPTUMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_LMA:
INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageAllocPTMemoryLMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_IOREMAP_PT_LMA:
INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageIORemapPTLMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_ALLOC_LMA_PAGES:
INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageAllocGPUMemLMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_ALLOC_UMA_PAGES:
INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageAllocGPUMemUMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_MAP_UMA_LMA_PAGES:
INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageMappedGPUMemUMA_LMA, uiBytes);
break;
case PVRSRV_MEM_ALLOC_TYPE_UMA_POOL_PAGES:
INCREASE_GLOBAL_STAT_VALUE(gsGlobalStats.ui32MemoryUsageAllocGPUMemUMAPool, uiBytes);
break;
default:
PVR_ASSERT(0);
break;
}
OSLockRelease(gsGlobalStats.hGlobalStatsLock);
}
/*************************************************************************/ /*!
@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)
{
PVRSRV_PROCESS_STATS* psProcessStats=NULL;
PVRSRV_ERROR eError;
IMG_PID currentPid = OSGetCurrentClientProcessIDKM();
IMG_BOOL bMoveProcess = IMG_FALSE;
#if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS)
IMG_CHAR acFolderName[30];
IMG_CHAR *pszProcName = OSGetCurrentProcessName();
strncpy(acFolderName, pszProcName, sizeof(acFolderName));
StripBadChars(acFolderName);
#endif
PVR_ASSERT(phProcessStats != NULL);
/* Check the PID has not already moved to the dead list... */
OSLockAcquire(g_psLinkedListLock);
psProcessStats = _FindProcessStatsInDeadList(currentPid);
if (psProcessStats != NULL)
{
/* Move it back onto the live list! */
_RemoveProcessStatsFromList(psProcessStats);
_AddProcessStatsToFrontOfLiveList(psProcessStats);
/* we can perform the OS operation out of lock */
bMoveProcess = IMG_TRUE;
}
else
{
/* Check the PID is not already registered in the live list... */
psProcessStats = _FindProcessStatsInLiveList(currentPid);
}
/* 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;
#if defined(ENABLE_DEBUGFS)
/* Check if we need to perform any OS operation */
if (bMoveProcess)
{
/* Transfer the OS entries back to the folder for live processes... */
_RemoveOSStatisticEntries(psProcessStats);
_CreateOSStatisticEntries(psProcessStats, pvOSLivePidFolder);
}
#endif
return PVRSRV_OK;
}
OSLockRelease(g_psLinkedListLock);
/* Allocate a new node structure and initialise it... */
psProcessStats = OSAllocZMemNoStats(sizeof(PVRSRV_PROCESS_STATS));
if (psProcessStats == NULL)
{
*phProcessStats = 0;
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
psProcessStats->eStructureType = PVRSRV_STAT_STRUCTURE_PROCESS;
psProcessStats->pid = currentPid;
psProcessStats->ui32RefCount = 1;
psProcessStats->ui32MemRefCount = 1;
psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_CONNECTIONS] = 1;
psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_MAX_CONNECTIONS] = 1;
eError = OSLockCreateNoStats(&psProcessStats->hLock ,LOCK_TYPE_NONE);
if (eError != PVRSRV_OK)
{
goto e0;
}
#if defined(PVRSRV_ENABLE_MEMORY_STATS)
psProcessStats->psMemoryStats = OSAllocZMemNoStats(sizeof(PVRSRV_MEMORY_STATS));
if (psProcessStats->psMemoryStats == NULL)
{
OSLockDestroyNoStats(psProcessStats->hLock);
goto e0;
}
psProcessStats->psMemoryStats->eStructureType = PVRSRV_STAT_STRUCTURE_MEMORY;
#endif
#if defined(PVR_RI_DEBUG)
psProcessStats->psRIMemoryStats = OSAllocZMemNoStats(sizeof(PVRSRV_RI_MEMORY_STATS));
if (psProcessStats->psRIMemoryStats == NULL)
{
OSLockDestroyNoStats(psProcessStats->hLock);
OSFreeMemNoStats(psProcessStats->psMemoryStats);
goto e0;
}
psProcessStats->psRIMemoryStats->eStructureType = PVRSRV_STAT_STRUCTURE_RIMEMORY;
psProcessStats->psRIMemoryStats->pid = currentPid;
#endif
#if defined(DEBUG)
psProcessStats->psCacheOpStats = OSAllocZMemNoStats(sizeof(PVRSRV_CACHEOP_STATS));
if (psProcessStats->psCacheOpStats == NULL)
{
OSLockDestroyNoStats(psProcessStats->hLock);
OSFreeMemNoStats(psProcessStats->psMemoryStats);
OSFreeMemNoStats(psProcessStats->psRIMemoryStats);
goto e0;
}
psProcessStats->psCacheOpStats->eStructureType = PVRSRV_STAT_STRUCTURE_CACHEOP;
#endif
/* Add it to the live list... */
OSLockAcquire(g_psLinkedListLock);
_AddProcessStatsToFrontOfLiveList(psProcessStats);
OSLockRelease(g_psLinkedListLock);
#if defined(ENABLE_DEBUGFS)
/* Create the process stat in the OS... */
#if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS)
OSSNPrintf(psProcessStats->szFolderName, sizeof(psProcessStats->szFolderName),
"%d_%s", currentPid, acFolderName);
#else
OSSNPrintf(psProcessStats->szFolderName, sizeof(psProcessStats->szFolderName),
"%d", currentPid);
#endif
_CreateOSStatisticEntries(psProcessStats, pvOSLivePidFolder);
#endif
/* Done */
*phProcessStats = (IMG_HANDLE) psProcessStats;
return PVRSRV_OK;
e0:
OSFreeMemNoStats(psProcessStats);
*phProcessStats = 0;
return PVRSRV_ERROR_OUT_OF_MEMORY;
} /* PVRSRVStatsRegisterProcess */
/*************************************************************************/ /*!
@Function PVRSRVStatsDeregisterProcess
@Input hProcessStats Handle to the process returned when registered.
@Description Method for destroying the statistics module data.
*/ /**************************************************************************/
void
PVRSRVStatsDeregisterProcess(IMG_HANDLE hProcessStats)
{
IMG_BOOL bMoveProcess = IMG_FALSE;
if (hProcessStats != 0)
{
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);
bMoveProcess = IMG_TRUE;
}else
#endif
{
OSLockRelease(psProcessStats->hLock);
}
}
OSLockRelease(g_psLinkedListLock);
#if defined(ENABLE_DEBUGFS)
/* The OS calls need to be performed without g_psLinkedListLock */
if (bMoveProcess == IMG_TRUE)
{
_MoveProcessToDeadListDebugFS(psProcessStats);
}
#endif
/* 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)
#if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) && defined(DEBUG)
{
_PVRSRVStatsAddMemAllocRecord(eAllocType, pvCpuVAddr, sCpuPAddr, uiBytes, pvPrivateData, NULL, 0);
}
void
_PVRSRVStatsAddMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE eAllocType,
void *pvCpuVAddr,
IMG_CPU_PHYADDR sCpuPAddr,
size_t uiBytes,
void *pvPrivateData,
void *pvAllocFromFile, IMG_UINT32 ui32AllocFromLine)
#endif
{
#if defined(PVRSRV_ENABLE_MEMORY_STATS)
IMG_PID currentPid = OSGetCurrentClientProcessIDKM();
IMG_PID currentCleanupPid = PVRSRVGetPurgeConnectionPid();
PVRSRV_DATA* psPVRSRVData = PVRSRVGetPVRSRVData();
PVRSRV_MEM_ALLOC_REC* psRecord = NULL;
PVRSRV_PROCESS_STATS* psProcessStats;
PVRSRV_MEMORY_STATS* psMemoryStats;
IMG_BOOL bResurrectProcess = IMG_FALSE;
/* Don't do anything if we are not initialised or we are shutting down! */
if (!bProcessStatsInitialised)
{
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);
bResurrectProcess = IMG_TRUE;
}
}
}
else
{
psProcessStats = _FindProcessStatsInLiveList(currentPid);
if (!psProcessStats)
{
psProcessStats = _FindProcessStatsInDeadList(currentPid);
bResurrectProcess = IMG_TRUE;
}
}
if (psProcessStats == NULL)
{
#if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS)
PVRSRV_ERROR eError;
IMG_CHAR acFolderName[30];
IMG_CHAR *pszProcName = OSGetCurrentProcessName();
strncpy(acFolderName, pszProcName, sizeof(acFolderName));
StripBadChars(acFolderName);
psProcessStats = OSAllocZMemNoStats(sizeof(PVRSRV_PROCESS_STATS));
if (psProcessStats == NULL)
{
OSLockRelease(g_psLinkedListLock);
return;
}
psProcessStats->eStructureType = PVRSRV_STAT_STRUCTURE_PROCESS;
psProcessStats->pid = currentPid;
psProcessStats->ui32RefCount = 1;
psProcessStats->ui32MemRefCount = 1;
psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_CONNECTIONS] = 1;
psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_MAX_CONNECTIONS] = 1;
eError = OSLockCreateNoStats(&psProcessStats->hLock ,LOCK_TYPE_NONE);
if (eError != PVRSRV_OK)
{
goto e0;
}
#if defined(PVRSRV_ENABLE_MEMORY_STATS)
psProcessStats->psMemoryStats = OSAllocZMemNoStats(sizeof(PVRSRV_MEMORY_STATS));
if (psProcessStats->psMemoryStats == NULL)
{
OSLockRelease(g_psLinkedListLock);
OSLockDestroyNoStats(psProcessStats->hLock);
psProcessStats->hLock = NULL;
goto e0;
}
psProcessStats->psMemoryStats->eStructureType = PVRSRV_STAT_STRUCTURE_MEMORY;
#endif
#if defined(PVR_RI_DEBUG)
psProcessStats->psRIMemoryStats = OSAllocZMemNoStats(sizeof(PVRSRV_RI_MEMORY_STATS));
if (psProcessStats->psRIMemoryStats == NULL)
{
OSFreeMemNoStats(psProcessStats->psMemoryStats);
OSLockDestroyNoStats(psProcessStats->hLock);
psProcessStats->hLock = NULL;
OSLockRelease(g_psLinkedListLock);
goto e0;
}
psProcessStats->psRIMemoryStats->eStructureType = PVRSRV_STAT_STRUCTURE_RIMEMORY;
psProcessStats->psRIMemoryStats->pid = currentPid;
#endif
#if defined(DEBUG)
psProcessStats->psCacheOpStats = OSAllocZMemNoStats(sizeof(PVRSRV_CACHEOP_STATS));
if (psProcessStats->psCacheOpStats == NULL)
{
OSFreeMemNoStats(psProcessStats->psRIMemoryStats);
OSFreeMemNoStats(psProcessStats->psMemoryStats);
OSLockDestroyNoStats(psProcessStats->hLock);
OSLockRelease(g_psLinkedListLock);
psProcessStats->hLock = NULL;
goto e0;
}
psProcessStats->psCacheOpStats->eStructureType = PVRSRV_STAT_STRUCTURE_CACHEOP;
#endif
OSLockRelease(g_psLinkedListLock);
/* Add it to the live list... */
_AddProcessStatsToFrontOfLiveList(psProcessStats);
/* Create the process stat in the OS... */
OSSNPrintf(psProcessStats->szFolderName, sizeof(psProcessStats->szFolderName),
"%d_%s", currentPid, acFolderName);
#if defined(ENABLE_DEBUGFS)
_CreateOSStatisticEntries(psProcessStats, pvOSLivePidFolder);
#endif
#else /* defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) */
OSLockRelease(g_psLinkedListLock);
#endif /* defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) */
}
else
{
OSLockRelease(g_psLinkedListLock);
}
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)", __FUNCTION__, currentPid, OSGetCurrentProcessName(), uiBytes));
#endif
if (psRecord != NULL)
{
OSFreeMemNoStats(psRecord);
}
return;
}
OSLockAcquireNested(psProcessStats->hLock, PROCESS_LOCK_SUBCLASS_CURRENT);
psMemoryStats = psProcessStats->psMemoryStats;
/* Insert the memory record... */
if (psRecord != NULL)
{
List_PVRSRV_MEM_ALLOC_REC_Insert(&psMemoryStats->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);
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);
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);
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);
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);
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);
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);
if (bResurrectProcess)
{
/* Move process from dead list to live list */
OSLockAcquire(g_psLinkedListLock);
_MoveProcessToLiveList(psProcessStats);
OSLockRelease(g_psLinkedListLock);
#if defined(ENABLE_DEBUGFS)
_MoveProcessToLiveListDebugFS(psProcessStats);
#endif
}
return;
#if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS)
e0:
OSFreeMemNoStats(psRecord);
OSFreeMemNoStats(psProcessStats);
return;
#endif
#endif
} /* PVRSRVStatsAddMemAllocRecord */
void
PVRSRVStatsRemoveMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE eAllocType,
IMG_UINT64 ui64Key)
{
#if defined(PVRSRV_ENABLE_MEMORY_STATS)
IMG_PID currentPid = OSGetCurrentClientProcessIDKM();
IMG_PID currentCleanupPid = PVRSRVGetPurgeConnectionPid();
PVRSRV_DATA* psPVRSRVData = PVRSRVGetPVRSRVData();
PVRSRV_PROCESS_STATS* psProcessStats = NULL;
PVRSRV_MEMORY_STATS* psMemoryStats = 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)
{
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)
{
psMemoryStats = psProcessStats->psMemoryStats;
psRecord = psMemoryStats->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)
{
psMemoryStats = psProcessStats->psMemoryStats;
psRecord = psMemoryStats->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)
{
psMemoryStats = psProcessStats->psMemoryStats;
psRecord = psMemoryStats->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);
#if defined(ENABLE_DEBUGFS)
_MoveProcessToDeadListDebugFS(psProcessStats);
#endif
/* 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 */
void
PVRSRVStatsIncrMemAllocStatAndTrack(PVRSRV_MEM_ALLOC_TYPE eAllocType,
size_t uiBytes,
IMG_UINT64 uiCpuVAddr)
{
IMG_BOOL bRes = IMG_FALSE;
_PVR_STATS_TRACKING_HASH_ENTRY *psNewTrackingHashEntry = NULL;
if (!bProcessStatsInitialised || (gpsSizeTrackingHashTable == NULL) )
{
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 = OSGetCurrentClientProcessIDKM();
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);
}
else
{
PVR_DPF((PVR_DBG_ERROR, "*** %s : @ line %d HASH_Insert() failed!!", __FUNCTION__, __LINE__));
}
}
else
{
PVR_DPF((PVR_DBG_ERROR, "*** %s : @ line %d Failed to alloc memory for psNewTrackingHashEntry!!", __FUNCTION__, __LINE__));
}
}
void
PVRSRVStatsIncrMemAllocStat(PVRSRV_MEM_ALLOC_TYPE eAllocType,
size_t uiBytes)
{
IMG_PID currentPid = OSGetCurrentClientProcessIDKM();
IMG_PID currentCleanupPid = PVRSRVGetPurgeConnectionPid();
PVRSRV_DATA* psPVRSRVData = PVRSRVGetPVRSRVData();
PVRSRV_PROCESS_STATS* psProcessStats = NULL;
IMG_BOOL bResurrectProcess = IMG_FALSE;
/* Don't do anything if we are not initialised or we are shutting down! */
if (!bProcessStatsInitialised)
{
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);
bResurrectProcess = IMG_TRUE;
}
}
}
else
{
psProcessStats = _FindProcessStatsInLiveList(currentPid);
if (!psProcessStats)
{
psProcessStats = _FindProcessStatsInDeadList(currentPid);
bResurrectProcess = IMG_TRUE;
}
}
if (psProcessStats == NULL)
{
#if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS)
PVRSRV_ERROR eError;
IMG_CHAR acFolderName[30];
IMG_CHAR *pszProcName = OSGetCurrentProcessName();
strncpy(acFolderName, pszProcName, sizeof(acFolderName));
StripBadChars(acFolderName);
if (bProcessStatsInitialised)
{
psProcessStats = OSAllocZMemNoStats(sizeof(PVRSRV_PROCESS_STATS));
if (psProcessStats == NULL)
{
return;
}
psProcessStats->eStructureType = PVRSRV_STAT_STRUCTURE_PROCESS;
psProcessStats->pid = currentPid;
psProcessStats->ui32RefCount = 1;
psProcessStats->ui32MemRefCount = 1;
psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_CONNECTIONS] = 1;
psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_MAX_CONNECTIONS] = 1;
eError = OSLockCreateNoStats(&psProcessStats->hLock ,LOCK_TYPE_NONE);
if (eError != PVRSRV_OK)
{
OSFreeMemNoStats(psProcessStats);
return;
}
#if defined(PVRSRV_ENABLE_MEMORY_STATS)
psProcessStats->psMemoryStats = OSAllocZMemNoStats(sizeof(PVRSRV_MEMORY_STATS));
if (psProcessStats->psMemoryStats == NULL)
{
OSLockDestroyNoStats(psProcessStats->hLock);
OSFreeMemNoStats(psProcessStats);
return;
}
psProcessStats->psMemoryStats->eStructureType = PVRSRV_STAT_STRUCTURE_MEMORY;
#endif
#if defined(PVR_RI_DEBUG)
psProcessStats->psRIMemoryStats = OSAllocZMemNoStats(sizeof(PVRSRV_RI_MEMORY_STATS));
if (psProcessStats->psRIMemoryStats == NULL)
{
OSFreeMemNoStats(psProcessStats->psMemoryStats);
OSLockDestroyNoStats(psProcessStats->hLock);
OSFreeMemNoStats(psProcessStats);
return;
}
psProcessStats->psRIMemoryStats->eStructureType = PVRSRV_STAT_STRUCTURE_RIMEMORY;
psProcessStats->psRIMemoryStats->pid = currentPid;
#endif
#if defined(PVR_RI_DEBUG)
psProcessStats->psCacheOpStats = OSAllocZMemNoStats(sizeof(PVRSRV_CACHEOP_STATS));
if (psProcessStats->psCacheOpStats == NULL)
{
OSFreeMemNoStats(psProcessStats->psMemoryStats);
OSFreeMemNoStats(psProcessStats->psRIMemoryStats);
OSLockDestroyNoStats(psProcessStats->hLock);
OSFreeMemNoStats(psProcessStats);
return;
}
psProcessStats->psCacheOpStats->eStructureType = PVRSRV_STAT_STRUCTURE_CACHEOP;
#endif
/* Add it to the live list... */
_AddProcessStatsToFrontOfLiveList(psProcessStats);
#if define(ENABLE_DEBUGFS)
/* Create the process stat in the OS... */
OSSNPrintf(psProcessStats->szFolderName, sizeof(psProcessStats->szFolderName),
"%d_%s", currentPid, acFolderName);
_CreateOSStatisticEntries(psProcessStats, pvOSLivePidFolder);
#endif
}
#else
OSLockRelease(g_psLinkedListLock);
#endif /* defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS) */
}
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... */
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);
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);
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);
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);
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);
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);
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);
if (bResurrectProcess)
{
/* Move process from dead list to live list */
OSLockAcquire(g_psLinkedListLock);
_MoveProcessToLiveList(psProcessStats);
OSLockRelease(g_psLinkedListLock);
#if defined(ENABLE_DEBUGFS)
_MoveProcessToLiveListDebugFS(psProcessStats);
#endif
}
}
}
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);
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);
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);
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);
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);
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);
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)
{
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);
}
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)
{
/* Decrement the memory stat... */
_DecreaseProcStatValue(eAllocType,
psProcessStats,
psTrackingHashEntry->uiSizeInBytes);
}
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 = OSGetCurrentClientProcessIDKM();
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);
#if defined(ENABLE_DEBUGFS)
_MoveProcessToDeadListDebugFS(psProcessStats);
#endif
/* 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)
{
/* Avoid signed / unsigned mismatch which is flagged by some compilers */
IMG_INT32 a, b;
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;
a=psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_FREELIST_PAGES_INIT];
b=(IMG_INT32)(ui32InitFLPages);
UPDATE_MAX_VALUE(a, b);
psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_FREELIST_PAGES_INIT]=a;
ui32InitFLPages=(IMG_UINT32)b;
a=psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_FREELIST_MAX_PAGES];
b=(IMG_INT32)ui32NumHighPages;
UPDATE_MAX_VALUE(a, b);
psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_FREELIST_PAGES_INIT]=a;
ui32InitFLPages=(IMG_UINT32)b;
OSLockRelease(psProcessStats->hLock);
}
OSLockRelease(g_psLinkedListLock);
} /* PVRSRVStatsUpdateFreelistStats */
#if defined(PVRSRV_ENABLE_PROCESS_STATS_DEBUGFS)
/*************************************************************************/ /*!
@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,
void *pvStatPtr,
OS_STATS_PRINTF_FUNC* pfnOSStatsPrintf)
{
PVRSRV_STAT_STRUCTURE_TYPE* peStructureType = (PVRSRV_STAT_STRUCTURE_TYPE*) pvStatPtr;
PVRSRV_PROCESS_STATS* psProcessStats = (PVRSRV_PROCESS_STATS*) pvStatPtr;
IMG_UINT32 ui32StatNumber = 0;
if (peStructureType == NULL || *peStructureType != PVRSRV_STAT_STRUCTURE_PROCESS)
{
PVR_ASSERT(peStructureType != NULL && *peStructureType == PVRSRV_STAT_STRUCTURE_PROCESS);
return;
}
if (pfnOSStatsPrintf == NULL)
{
return;
}
/* Loop through all the values and print them... */
while (ui32StatNumber < PVRSRV_PROCESS_STAT_TYPE_COUNT)
{
if (psProcessStats->ui32MemRefCount > 0)
{
pfnOSStatsPrintf(pvFile, pszProcessStatFmt[ui32StatNumber], psProcessStats->i32StatValue[ui32StatNumber]);
}
else
{
PVR_DPF((PVR_DBG_ERROR, "%s: Called with psProcessStats->ui32MemRefCount=%d", __FUNCTION__, psProcessStats->ui32MemRefCount));
}
ui32StatNumber++;
}
} /* ProcessStatsPrintElements */
#endif
#if defined(DEBUG)
/* Divide a number by 10 using shifts only */
static INLINE IMG_UINT64 DivBy10(IMG_UINT64 uiNum)
{
IMG_UINT64 uiQuot;
IMG_UINT64 uiRem;
uiQuot = (uiNum >> 1) + (uiNum >> 2);
uiQuot = uiQuot + (uiQuot >> 4);
uiQuot = uiQuot + (uiQuot >> 8);
uiQuot = uiQuot + (uiQuot >> 16);
uiQuot = uiQuot >> 3;
uiRem = uiNum - (((uiQuot << 2) + uiQuot) << 1);
return uiQuot + (uiRem > 9);
}
void
PVRSRVStatsUpdateCacheOpStats(PVRSRV_CACHE_OP uiCacheOp,
IMG_UINT32 ui32OpSeqNum,
#if defined(PVR_RI_DEBUG)
IMG_DEV_VIRTADDR sDevVAddr,
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 bHasTimeline,
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(PVR_RI_DEBUG)
psProcessStats->asCacheOp[Idx].sDevVAddr = sDevVAddr;
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].bHasTimeline = bHasTimeline;
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,
void *pvStatPtr,
OS_STATS_PRINTF_FUNC* pfnOSStatsPrintf)
{
PVRSRV_STAT_STRUCTURE_TYPE* peStructureType = (PVRSRV_STAT_STRUCTURE_TYPE*) pvStatPtr;
PVRSRV_PROCESS_STATS* psProcessStats = (PVRSRV_PROCESS_STATS*) pvStatPtr;
IMG_CHAR *pszCacheOpType, *pszFlushType, *pszFlushMode;
IMG_INT32 i32WriteIdx, i32ReadIdx;
#if defined(PVR_RI_DEBUG)
#define CACHEOP_RI_PRINTF_HEADER \
"%-10s %-10s %-5s %-16s %-10s %-10s %-12s %-12s\n"
#define CACHEOP_RI_PRINTF_FENCE \
"%-10s %-10s %-5s %-16s %-10s %-10s %-12llu 0x%-10x\n"
#define CACHEOP_RI_PRINTF \
"%-10s %-10s %-5s 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
if (peStructureType == NULL ||
*peStructureType != PVRSRV_STAT_STRUCTURE_PROCESS ||
psProcessStats->psCacheOpStats->eStructureType != PVRSRV_STAT_STRUCTURE_CACHEOP)
{
PVR_ASSERT(peStructureType != NULL);
PVR_ASSERT(*peStructureType == PVRSRV_STAT_STRUCTURE_PROCESS);
PVR_ASSERT(psProcessStats->psCacheOpStats->eStructureType == PVRSRV_STAT_STRUCTURE_CACHEOP);
return;
}
if (pfnOSStatsPrintf == NULL)
{
return;
}
/* File header info */
pfnOSStatsPrintf(pvFile,
#if defined(PVR_RI_DEBUG)
CACHEOP_RI_PRINTF_HEADER,
#else
CACHEOP_PRINTF_HEADER,
#endif
"CacheOp",
"Type",
"Mode",
#if defined(PVR_RI_DEBUG)
"DevVAddr",
#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;
}
/* Convert nano-seconds to micro-seconds */
ui64ExecuteTime = psProcessStats->asCacheOp[i32ReadIdx].ui64ExecuteTime;
ui64ExecuteTime = DivBy10(DivBy10(DivBy10(ui64ExecuteTime)));
if (psProcessStats->asCacheOp[i32ReadIdx].bIsFence)
{
IMG_CHAR *pszFenceType = "";
pszCacheOpType = "Fence";
#if defined(PVR_RI_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;
case RGXFWIF_DM_RTU:
pszFenceType = "RTU";
break;
case RGXFWIF_DM_SHG:
pszFenceType = "SHG";
break;
default:
PVR_ASSERT(0);
break;
}
#endif
pfnOSStatsPrintf(pvFile,
#if defined(PVR_RI_DEBUG)
CACHEOP_RI_PRINTF_FENCE,
#else
CACHEOP_PRINTF_FENCE,
#endif
pszCacheOpType,
pszFenceType,
"",
#if defined(PVR_RI_DEBUG)
"",
#endif
"",
"",
ui64ExecuteTime,
psProcessStats->asCacheOp[i32ReadIdx].ui32OpSeqNum);
}
else if (psProcessStats->asCacheOp[i32ReadIdx].bHasTimeline)
{
pfnOSStatsPrintf(pvFile,
#if defined(PVR_RI_DEBUG)
CACHEOP_RI_PRINTF_FENCE,
#else
CACHEOP_PRINTF_FENCE,
#endif
"Timeline",
"",
"",
#if defined(PVR_RI_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(PVR_RI_DEBUG)
CACHEOP_RI_PRINTF,
#else
CACHEOP_PRINTF,
#endif
pszCacheOpType,
pszFlushType,
pszFlushMode,
#if defined(PVR_RI_DEBUG)
psProcessStats->asCacheOp[i32ReadIdx].sDevVAddr.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,
void *pvStatPtr,
OS_STATS_PRINTF_FUNC* pfnOSStatsPrintf)
{
PVRSRV_STAT_STRUCTURE_TYPE* peStructureType = (PVRSRV_STAT_STRUCTURE_TYPE*) pvStatPtr;
PVRSRV_MEMORY_STATS* psMemoryStats = (PVRSRV_MEMORY_STATS*) pvStatPtr;
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;
if (peStructureType == NULL || *peStructureType != PVRSRV_STAT_STRUCTURE_MEMORY)
{
PVR_ASSERT(peStructureType != NULL && *peStructureType == PVRSRV_STAT_STRUCTURE_MEMORY);
return;
}
if (pfnOSStatsPrintf == NULL)
{
return;
}
/* Write the header... */
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");
/* The lock has to be held whilst moving through the memory list... */
OSLockAcquire(g_psLinkedListLock);
psRecord = psMemoryStats->psMemoryRecords;
while (psRecord != NULL)
{
IMG_BOOL bPrintStat = IMG_TRUE;
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;
}
OSLockRelease(g_psLinkedListLock);
} /* MemStatsPrintElements */
#endif
#if defined(PVR_RI_DEBUG_DEBUGFS)
/*************************************************************************/ /*!
@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,
void *pvStatPtr,
OS_STATS_PRINTF_FUNC* pfnOSStatsPrintf)
{
PVRSRV_STAT_STRUCTURE_TYPE *peStructureType = (PVRSRV_STAT_STRUCTURE_TYPE*) pvStatPtr;
PVRSRV_RI_MEMORY_STATS *psRIMemoryStats = (PVRSRV_RI_MEMORY_STATS*) pvStatPtr;
IMG_CHAR *pszStatFmtText = NULL;
IMG_HANDLE *pRIHandle = NULL;
if (peStructureType == NULL || *peStructureType != PVRSRV_STAT_STRUCTURE_RIMEMORY)
{
PVR_ASSERT(peStructureType != NULL && *peStructureType == PVRSRV_STAT_STRUCTURE_RIMEMORY);
return;
}
if (pfnOSStatsPrintf == NULL)
{
return;
}
/*
* Loop through the RI system to get each line of text.
*/
while (RIGetListEntryKM(psRIMemoryStats->pid,
&pRIHandle,
&pszStatFmtText))
{
pfnOSStatsPrintf(pvFile, "%s", pszStatFmtText);
}
} /* RIMemStatsPrintElements */
#endif
static IMG_UINT32 ui32FirmwareStartTimestamp=0;
static IMG_UINT64 ui64FirmwareIdleDuration=0;
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)
{
#if !defined(PVR_DISABLE_KMALLOC_MEMSTATS)
pfnOSGetStatsPrintf(pvFile, "MemoryUsageKMalloc %10d\n", gsGlobalStats.ui32MemoryUsageKMalloc);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageKMallocMax %10d\n", gsGlobalStats.ui32MemoryUsageKMallocMax);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageVMalloc %10d\n", gsGlobalStats.ui32MemoryUsageVMalloc);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageVMallocMax %10d\n", gsGlobalStats.ui32MemoryUsageVMallocMax);
#endif
pfnOSGetStatsPrintf(pvFile, "MemoryUsageAllocPTMemoryUMA %10d\n", gsGlobalStats.ui32MemoryUsageAllocPTMemoryUMA);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageAllocPTMemoryUMAMax %10d\n", gsGlobalStats.ui32MemoryUsageAllocPTMemoryUMAMax);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageVMapPTUMA %10d\n", gsGlobalStats.ui32MemoryUsageVMapPTUMA);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageVMapPTUMAMax %10d\n", gsGlobalStats.ui32MemoryUsageVMapPTUMAMax);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageAllocPTMemoryLMA %10d\n", gsGlobalStats.ui32MemoryUsageAllocPTMemoryLMA);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageAllocPTMemoryLMAMax %10d\n", gsGlobalStats.ui32MemoryUsageAllocPTMemoryLMAMax);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageIORemapPTLMA %10d\n", gsGlobalStats.ui32MemoryUsageIORemapPTLMA);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageIORemapPTLMAMax %10d\n", gsGlobalStats.ui32MemoryUsageIORemapPTLMAMax);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageAllocGPUMemLMA %10d\n", gsGlobalStats.ui32MemoryUsageAllocGPUMemLMA);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageAllocGPUMemLMAMax %10d\n", gsGlobalStats.ui32MemoryUsageAllocGPUMemLMAMax);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageAllocGPUMemUMA %10d\n", gsGlobalStats.ui32MemoryUsageAllocGPUMemUMA);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageAllocGPUMemUMAMax %10d\n", gsGlobalStats.ui32MemoryUsageAllocGPUMemUMAMax);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageAllocGPUMemUMAPool %10d\n", gsGlobalStats.ui32MemoryUsageAllocGPUMemUMAPool);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageAllocGPUMemUMAPoolMax %10d\n", gsGlobalStats.ui32MemoryUsageAllocGPUMemUMAPoolMax);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageMappedGPUMemUMA/LMA %10d\n", gsGlobalStats.ui32MemoryUsageMappedGPUMemUMA_LMA);
pfnOSGetStatsPrintf(pvFile, "MemoryUsageMappedGPUMemUMA/LMAMax %10d\n", gsGlobalStats.ui32MemoryUsageMappedGPUMemUMA_LMAMax);
}
}
#if defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS)
static void StripBadChars( IMG_CHAR *psStr)
{
IMG_INT cc;
/* Remove any '/' chars that may be in the ProcName (kernel thread could contain these) */
for (cc=0; cc<30; cc++)
{
if( *psStr == '/')
{
*psStr = '-';
}
psStr++;
}
}
#endif