|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
perfthrd.c
Abstract:
This file implements an Performance Object that presents Thread performance object data
Created:
Bob Watson 22-Oct-1996
Revision History
--*/ //
// Include Files
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <assert.h>
#include <winperf.h>
#include <ntprfctr.h>
#include <perfutil.h>
#include "perfsprc.h"
#include "perfmsg.h"
#include "datathrd.h"
extern DWORD PerfSprc_dwThreadNameFormat;
DWORD APIENTRY CollectThreadObjectData ( IN OUT LPVOID *lppData, IN OUT LPDWORD lpcbTotalBytes, IN OUT LPDWORD lpNumObjectTypes ) /*++
Routine Description:
This routine will return the data for the processor object
Arguments:
IN OUT LPVOID *lppData IN: pointer to the address of the buffer to receive the completed PerfDataBlock and subordinate structures. This routine will append its data to the buffer starting at the point referenced by *lppData. OUT: points to the first byte after the data structure added by this routine. This routine updated the value at lppdata after appending its data.
IN OUT LPDWORD lpcbTotalBytes IN: the address of the DWORD that tells the size in bytes of the buffer referenced by the lppData argument OUT: the number of bytes added by this routine is writted to the DWORD pointed to by this argument
IN OUT LPDWORD NumObjectTypes IN: the address of the DWORD to receive the number of objects added by this routine OUT: the number of objects added by this routine is writted to the DWORD pointed to by this argument
Returns:
0 if successful, else Win 32 error code of failure
--*/ { LONG lReturn = ERROR_SUCCESS;
DWORD TotalLen; // Length of the total return block
THREAD_DATA_DEFINITION *pThreadDataDefinition; PERF_INSTANCE_DEFINITION *pPerfInstanceDefinition; PTHREAD_COUNTER_DATA pTCD; THREAD_COUNTER_DATA tcdTotal;
PSYSTEM_PROCESS_INFORMATION ProcessInfo; PSYSTEM_THREAD_INFORMATION ThreadInfo; ULONG ProcessNumber; ULONG NumThreadInstances; ULONG ThreadNumber; ULONG ProcessBufferOffset; BOOLEAN NullProcess; BOOL bMoreThreads;
// total thread accumulator variables
UNICODE_STRING ThreadName; WCHAR ThreadNameBuffer[MAX_THREAD_NAME_LENGTH+1];
pThreadDataDefinition = (THREAD_DATA_DEFINITION *) *lppData;
//
// Check for sufficient space for Thread object type definition
//
TotalLen = sizeof(THREAD_DATA_DEFINITION) + sizeof(PERF_INSTANCE_DEFINITION) + sizeof(THREAD_COUNTER_DATA);
if ( *lpcbTotalBytes < TotalLen ) { *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_MORE_DATA; }
//
// Define Thread data block
//
ThreadName.Length = ThreadName.MaximumLength = (MAX_THREAD_NAME_LENGTH + 1) * sizeof(WCHAR); ThreadName.Buffer = ThreadNameBuffer;
memcpy(pThreadDataDefinition, &ThreadDataDefinition, sizeof(THREAD_DATA_DEFINITION));
pThreadDataDefinition->ThreadObjectType.PerfTime = PerfTime;
ProcessBufferOffset = 0;
// Now collect data for each Thread
ProcessNumber = 0; NumThreadInstances = 0;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pProcessBuffer;
pPerfInstanceDefinition = (PPERF_INSTANCE_DEFINITION)&pThreadDataDefinition[1]; TotalLen = sizeof(THREAD_DATA_DEFINITION);
// clear total accumulator
memset (&tcdTotal, 0, sizeof (tcdTotal));
bMoreThreads = FALSE; if (ProcessInfo) { if (ProcessInfo->NextEntryOffset != 0) { bMoreThreads = TRUE; } } while ( bMoreThreads && (ProcessInfo != NULL)) {
if ( ProcessInfo->ImageName.Buffer != NULL || ProcessInfo->NumberOfThreads > 0 ) { NullProcess = FALSE; } else { NullProcess = TRUE; }
ThreadNumber = 0; // Thread number of this process
ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
while ( !NullProcess && ThreadNumber < ProcessInfo->NumberOfThreads ) {
TotalLen += sizeof(PERF_INSTANCE_DEFINITION) + (MAX_THREAD_NAME_LENGTH+1+sizeof(DWORD))* sizeof(WCHAR) + sizeof (THREAD_COUNTER_DATA);
if ( *lpcbTotalBytes < TotalLen ) { *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_MORE_DATA; }
if (PerfSprc_dwThreadNameFormat == NAME_FORMAT_ID) { PerfIntegerToWString( HandleToUlong(ThreadInfo->ClientId.UniqueThread), 10, MAX_THREAD_NAME_LENGTH+1, ThreadNameBuffer); } else { // The only name we've got is the thread number
RtlIntegerToUnicodeString(ThreadNumber, 10, &ThreadName); }
MonBuildInstanceDefinition(pPerfInstanceDefinition, (PVOID *) &pTCD, PROCESS_OBJECT_TITLE_INDEX, ProcessNumber, (DWORD)-1, ThreadName.Buffer);
// test structure for Quadword Alignment
assert (((DWORD)(pTCD) & 0x00000007) == 0);
//
//
// Format and collect Thread data
//
pTCD->CounterBlock.ByteLength = sizeof(THREAD_COUNTER_DATA);
//
// Convert User time from 100 nsec units to counter
// frequency.
//
tcdTotal.ProcessorTime += pTCD->ProcessorTime = ThreadInfo->KernelTime.QuadPart + ThreadInfo->UserTime.QuadPart;
tcdTotal.UserTime += pTCD->UserTime = ThreadInfo->UserTime.QuadPart; tcdTotal.KernelTime += pTCD->KernelTime = ThreadInfo->KernelTime.QuadPart;
tcdTotal.ContextSwitches += pTCD->ContextSwitches = ThreadInfo->ContextSwitches;
pTCD->ThreadElapsedTime = ThreadInfo->CreateTime.QuadPart;
pTCD->ThreadPriority = (ThreadInfo->ClientId.UniqueProcess == 0) ? 0 : ThreadInfo->Priority;
pTCD->ThreadBasePriority = ThreadInfo->BasePriority; pTCD->ThreadStartAddr = ThreadInfo->StartAddress; pTCD->ThreadState = (DWORD)((ThreadInfo->ThreadState > 7) ? 7 : ThreadInfo->ThreadState); pTCD->WaitReason = (DWORD)ThreadInfo->WaitReason;
// now stuff in the process and thread id's
pTCD->ProcessId = HandleToUlong(ThreadInfo->ClientId.UniqueProcess); pTCD->ThreadId = HandleToUlong(ThreadInfo->ClientId.UniqueThread);
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pTCD[1];
NumThreadInstances++; ThreadNumber++; ThreadInfo++; }
if ( !NullProcess ) { ProcessNumber++; }
if (ProcessInfo->NextEntryOffset == 0) { bMoreThreads = FALSE; continue; }
ProcessBufferOffset += ProcessInfo->NextEntryOffset; ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) &pProcessBuffer[ProcessBufferOffset]; }
if (NumThreadInstances > 0) {
// See if the total instance will fit
TotalLen += sizeof(PERF_INSTANCE_DEFINITION) + (MAX_THREAD_NAME_LENGTH+1+sizeof(DWORD))* sizeof(WCHAR) + sizeof (THREAD_COUNTER_DATA);
if ( *lpcbTotalBytes < TotalLen ) { *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_MORE_DATA; }
// set the Total Elapsed Time to be the current time so that it will
// show up as 0 when displayed.
tcdTotal.ThreadElapsedTime = pThreadDataDefinition->ThreadObjectType.PerfTime.QuadPart;
// use the "total" for this instance
MonBuildInstanceDefinition(pPerfInstanceDefinition, (PVOID *) &pTCD, PROCESS_OBJECT_TITLE_INDEX, ProcessNumber, (DWORD)-1, wszTotal);
// test structure for Quadword Alignment
assert (((DWORD)(pTCD) & 0x00000007) == 0);
//
//
// Format and collect Thread data
//
memcpy (pTCD, &tcdTotal, sizeof(tcdTotal)); pTCD->CounterBlock.ByteLength = sizeof(THREAD_COUNTER_DATA);
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pTCD[1];
NumThreadInstances++; } // Note number of Thread instances
pThreadDataDefinition->ThreadObjectType.NumInstances = NumThreadInstances;
//
// Now we know how large an area we used for the
// Thread definition, so we can update the offset
// to the next object definition
//
*lpcbTotalBytes = pThreadDataDefinition->ThreadObjectType.TotalByteLength = (DWORD)((PCHAR) pPerfInstanceDefinition - (PCHAR) pThreadDataDefinition);
#if DBG
if (*lpcbTotalBytes > TotalLen ) { DbgPrint ("\nPERFPROC: Thread Perf Ctr. Instance Size Underestimated:"); DbgPrint ("\nPERFPROC: Estimated size: %d, Actual Size: %d", TotalLen, *lpcbTotalBytes); } #endif
*lppData = (LPVOID)pPerfInstanceDefinition;
*lpNumObjectTypes = 1;
return lReturn;
}
|