You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
312 lines
8.0 KiB
312 lines
8.0 KiB
/**************************************************************************
|
|
*
|
|
* Copyright (c) 2000 Microsoft Corporation
|
|
*
|
|
* Module Name:
|
|
*
|
|
* IceCAP user counters for GDI+ memory allocations
|
|
*
|
|
* Abstract:
|
|
*
|
|
* This is an IceCAP "user counter" DLL. It exports logging functions which
|
|
* GDI+ will call during memory allocation (if PROFILE_MEMORY_USAGE is
|
|
* true). It also exports query functions for hooking up to IceCAP.
|
|
*
|
|
* Instructions for use:
|
|
*
|
|
* + Build memcounter.dll
|
|
* + Copy memcounter.dll and the icecap.ini file (which is in the same
|
|
* directory as memcounter.cpp) to the test app directory.
|
|
* + set PROFILE_MEMORY_USAGE=1
|
|
* + Build GDIPLUS.DLL
|
|
* + Instrument it (using "gppick.bat")
|
|
* + Run the test
|
|
* + Afterwards, view the .ICP file that has been generated.
|
|
*
|
|
* In the IceCAP viewer, you will need to add columns for
|
|
* "User counter 1, elapsed inclusive", etc.
|
|
*
|
|
* Created:
|
|
*
|
|
* 06/10/2000 agodfrey
|
|
* Created it from the sample code in IceCAP4\Samples\MemTrack.
|
|
*
|
|
**************************************************************************/
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#define DONTUSEICECAPLIB
|
|
#include "icecap.h"
|
|
|
|
// GLOBALS
|
|
//
|
|
// This is where we will store our counter values. These could
|
|
// just as easily be put in shared memory so you can have another
|
|
// process updating them. They can not be put in the counter
|
|
// functions as auto variables, since naked functions don't
|
|
// allow for this.
|
|
|
|
DWORD g_dwTlsSlot = 0xffffffff; // TLS Slot, allocated in DllMain
|
|
DWORD g_dwTlsIndexSize; // 'Pre-computed' slot offset, so we can
|
|
// avoid calling TlsGetValue in probes
|
|
|
|
//
|
|
// Data tracked for each thread.
|
|
struct SAllocInfo
|
|
{
|
|
COUNTER cntAllocs; // Number of allocations made
|
|
COUNTER cntBytes; // Bytes (total) allocated
|
|
};
|
|
|
|
|
|
const UINT g_uiMaxThreads = 64; // Max sim. threads tracked
|
|
SAllocInfo g_aAllocInfo[g_uiMaxThreads]; // Data tracked
|
|
BOOL g_afInUse[g_uiMaxThreads]; // Is a particular data slot used
|
|
|
|
|
|
// FUNCTIONS
|
|
//
|
|
///////////////////////////////////////////////////////////////
|
|
// DllMain
|
|
//
|
|
// Standard DLL entry point, sets up storage for per-thread
|
|
// counter information.
|
|
//
|
|
// History: 9-16-98 MHotchin Created
|
|
//
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
BOOL
|
|
APIENTRY
|
|
DllMain(
|
|
HANDLE ,
|
|
DWORD dwReason,
|
|
LPVOID )
|
|
{
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
g_dwTlsSlot = TlsAlloc();
|
|
|
|
memset(g_afInUse, 0, sizeof(g_afInUse));
|
|
|
|
if (g_dwTlsSlot == 0xffffffff)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Tricky, tricky, tricky...
|
|
// We can pre-compute where the TLS slot will be, once
|
|
// we have the index. The offsets are OS dependent!
|
|
//
|
|
// This makes the probes much faster, becuase we don't need to
|
|
// call TlsGetValue().
|
|
if (GetVersion() & 0x80000000)
|
|
{
|
|
// *** WIN 9x ONLY ***
|
|
g_dwTlsIndexSize = g_dwTlsSlot * sizeof(void *) + 0x88;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// *** NT ONLY ***
|
|
g_dwTlsIndexSize = g_dwTlsSlot * sizeof(void *) + 0xe10;
|
|
}
|
|
|
|
//
|
|
// FALL THROUGH
|
|
case DLL_THREAD_ATTACH:
|
|
{
|
|
SAllocInfo *pInfo = NULL;
|
|
|
|
//
|
|
// Locate a data slot for this thread and remeber it's pointer
|
|
// in the TLS slot.
|
|
for (UINT i = 0; i < g_uiMaxThreads; i++)
|
|
{
|
|
if (!g_afInUse[i])
|
|
{
|
|
g_afInUse[i] = TRUE;
|
|
pInfo = &(g_aAllocInfo[i]);
|
|
memset(pInfo, 0, sizeof(SAllocInfo));
|
|
|
|
break;
|
|
}
|
|
}
|
|
TlsSetValue(g_dwTlsSlot, pInfo);
|
|
}
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
if (g_dwTlsSlot != 0xffffffff)
|
|
{
|
|
TlsFree(g_dwTlsSlot);
|
|
g_dwTlsSlot = 0xffffffff;
|
|
}
|
|
break;
|
|
|
|
case DLL_THREAD_DETACH:
|
|
{
|
|
SAllocInfo *pInfo = (SAllocInfo *)TlsGetValue(g_dwTlsSlot);
|
|
|
|
if (pInfo != NULL)
|
|
{
|
|
UINT iIndex = pInfo - g_aAllocInfo;
|
|
|
|
g_afInUse[iIndex] = FALSE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// GetCounterInfo
|
|
//
|
|
// This is where we define what is counter is, and how it
|
|
// behaves.
|
|
//
|
|
// History: 9-16-98 MHotchin Created
|
|
// 2-26-99 AlonB updated for new USERCOUNTER API
|
|
//
|
|
///////////////////////////////////////////////////////////////
|
|
extern "C" BOOL _stdcall GetCounterInfo(DWORD iCounter, USERCOUNTERINFO *pInfo)
|
|
|
|
{
|
|
// we only have two counters to set up
|
|
if (iCounter > 1)
|
|
return FALSE;
|
|
|
|
pInfo->dwSize = sizeof(USERCOUNTERINFO);
|
|
pInfo->bSynchronized = TRUE;
|
|
|
|
if (0 == iCounter)
|
|
{
|
|
// SETUP COUNTER 0
|
|
strcpy(pInfo->szCounterFuncName, "GetCounterOneValue");
|
|
strcpy(pInfo->szName, "Mem Allocs");
|
|
pInfo->ct = MonotonicallyIncreasing;
|
|
}
|
|
else // 1 == iCounter
|
|
{
|
|
// SETUP COUNTER 1
|
|
strcpy(pInfo->szCounterFuncName, "GetCounterTwoValue");
|
|
strcpy(pInfo->szName, "Byte Allocs");
|
|
pInfo->ct = RandomIncreasing;
|
|
}
|
|
|
|
// We didn't do anything here that could fail, at least nothing
|
|
// that wouldn't be catistrophic. So just return TRUE.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
extern "C"
|
|
VOID _stdcall
|
|
MC_LogAllocation(UINT size)
|
|
{
|
|
//
|
|
// Get data pointer from TLS slot and update counts for this thread.
|
|
if (g_dwTlsSlot != 0xffffffff)
|
|
{
|
|
SAllocInfo *pAllocInfo = (SAllocInfo *)TlsGetValue(g_dwTlsSlot);
|
|
|
|
if (pAllocInfo != NULL)
|
|
{
|
|
pAllocInfo->cntAllocs++;
|
|
pAllocInfo->cntBytes += size;
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C"
|
|
BOOL
|
|
_stdcall
|
|
InitCounters(void)
|
|
{
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
#define PcTeb 0x18
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetCounterOneValue
|
|
//
|
|
// Return current value for first counter - number of CRT allocs
|
|
//
|
|
// History: 9-16-98 MHotchin Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
extern "C"
|
|
COUNTER
|
|
_declspec(naked) _stdcall
|
|
GetCounterOneValue(void)
|
|
{
|
|
_asm
|
|
{
|
|
mov eax, g_dwTlsIndexSize // Load TLS slot offset
|
|
add eax, fs:[PcTeb] // Load pointer to TLS slot
|
|
mov eax, [eax] // Load Data pointer from TLS slot
|
|
je NoSample // If NULL, skip
|
|
|
|
mov edx, dword ptr [eax+0x04] // High word of # allocs
|
|
mov eax, dword ptr [eax] // Low word of # allocs
|
|
|
|
ret
|
|
NoSample:
|
|
mov eax, 0
|
|
mov edx, 0
|
|
|
|
ret
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetCounterTwoValue
|
|
//
|
|
// Return current value of second counter - number of bytes allocated.
|
|
//
|
|
// History: 9-16-98 MHotchin Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
extern "C"
|
|
COUNTER
|
|
_declspec(naked) _stdcall
|
|
GetCounterTwoValue(void)
|
|
{
|
|
_asm
|
|
{
|
|
mov eax, g_dwTlsIndexSize // Load TLS slot offset
|
|
add eax, fs:[PcTeb] // Load pointer to TLS slot
|
|
mov eax, [eax] // Load Data pointer from TLS slot
|
|
je NoSample // If NULL, skip
|
|
|
|
mov edx, dword ptr [eax+0x0c] // High wors of # bytes
|
|
mov eax, dword ptr [eax+0x08] // Low word of # bytes
|
|
|
|
ret
|
|
NoSample:
|
|
mov eax, 0
|
|
mov edx, 0
|
|
|
|
ret
|
|
}
|
|
}
|
|
|
|
|
|
|