/*++ Copyright (c) 1997-2000 Microsoft Corporation Module Name: process.c Abstract: Manipulation routines for cpdata structures. Author: Melur Raghuraman (mraghu) 03-Oct-1997 Environment: Revision History: --*/ #include #include #include "cpdata.h" #include "tracectr.h" #include "item.h" extern PTRACE_CONTEXT_BLOCK TraceContext; extern PWCHAR CpdiGuidToString(PWCHAR s, LPGUID piid); VOID InitDiskRecord( PTDISK_RECORD pDisk, ULONG DiskNumber ) { PWCHAR name; if (pDisk == NULL){ return; } memset(pDisk, 0, sizeof(TDISK_RECORD)); InitializeListHead(&pDisk->ProcessListHead); InitializeListHead(&pDisk->FileListHead); pDisk->DiskNumber = DiskNumber; name = (PWCHAR)malloc(16 * sizeof(WCHAR)); if (name != NULL) { wsprintfW(name, L"Disk%d", DiskNumber); } pDisk->DiskName = name; } VOID InitFileRecord( PFILE_RECORD pFile ) { if (pFile == NULL){ return; } memset(pFile, 0, sizeof(FILE_RECORD)); InitializeListHead(&pFile->ProtoProcessListHead); } VOID InitThreadRecord( PTHREAD_RECORD pThread ) { if (pThread == NULL) return; memset(pThread, 0, sizeof(THREAD_RECORD)); InitializeListHead( &pThread->DiskListHead ); InitializeListHead( &pThread->TransListHead ); InitializeListHead( &pThread->HPFReadListHead ); InitializeListHead( &pThread->HPFWriteListHead ); } VOID InitTransRecord( PTRANS_RECORD pTrans ) { if (pTrans == NULL) return; memset(pTrans, 0, sizeof(TRANS_RECORD)); InitializeListHead(&pTrans->SubTransListHead); } VOID InitMofData( PMOF_DATA pMofData ) { if (pMofData == NULL) return; memset(pMofData, 0, sizeof(MOF_DATA)); pMofData->MaxKCpu = -1; pMofData->MinKCpu = -1; pMofData->MaxUCpu = -1; pMofData->MinUCpu = -1; } VOID InitProcessRecord( PPROCESS_RECORD pProcess ) { if (pProcess == NULL) return; memset(pProcess, 0, sizeof(PROCESS_RECORD)); InitializeListHead( &pProcess->ThreadListHead ); InitializeListHead( &pProcess->DiskListHead ); InitializeListHead( &pProcess->FileListHead ); InitializeListHead( &pProcess->ModuleListHead ); InitializeListHead( &pProcess->HPFListHead ); } BOOLEAN AddModuleRecord(PMODULE_RECORD * ppModule, ULONG lBaseAddress, ULONG lModuleSize, WCHAR * strModuleName) { PMODULE_RECORD pModule; if ( (ppModule == NULL) || (strModuleName == NULL) ) { return FALSE; } pModule = (PMODULE_RECORD)malloc(sizeof(MODULE_RECORD)); if(NULL != pModule){ memset(pModule, 0, sizeof(MODULE_RECORD)); pModule->strModuleName = malloc(sizeof(WCHAR) * (lstrlenW(strModuleName) + 1)); if (pModule->strModuleName == NULL) { free(pModule); pModule = NULL; } else { wcscpy(pModule->strModuleName, strModuleName); pModule->lBaseAddress = lBaseAddress; pModule->lModuleSize = lModuleSize; } } * ppModule = pModule; return (BOOLEAN) (* ppModule != NULL); } BOOLEAN AddHPFFileRecord( PHPF_FILE_RECORD * ppHPFFileRecord, ULONG RecordID, ULONG IrpFlags, ULONG DiskNumber, ULONGLONG ByteOffset, ULONG BytesCount, PVOID fDO ) { PHPF_FILE_RECORD pHPFFileRecord = malloc(sizeof(HPF_FILE_RECORD)); if (pHPFFileRecord) { pHPFFileRecord->RecordID = RecordID; pHPFFileRecord->IrpFlags = IrpFlags; pHPFFileRecord->DiskNumber = DiskNumber; pHPFFileRecord->ByteOffset = ByteOffset; pHPFFileRecord->BytesCount = BytesCount; pHPFFileRecord->fDO = fDO; } * ppHPFFileRecord = pHPFFileRecord; return (BOOLEAN) (* ppHPFFileRecord != NULL); } BOOLEAN AddHPFRecord( PHPF_RECORD * ppHPFRecord, ULONG lFaultAddress, PVOID fDO, LONG ByteCount, LONGLONG ByteOffset ) { PHPF_RECORD pHPFRecord = malloc(sizeof(HPF_RECORD)); if (pHPFRecord) { pHPFRecord->fDO = fDO; pHPFRecord->lFaultAddress = lFaultAddress; pHPFRecord->lByteCount = ByteCount; pHPFRecord->lByteOffset = ByteOffset; InitializeListHead(& pHPFRecord->HPFReadListHead); } * ppHPFRecord = pHPFRecord; return (BOOLEAN) (* ppHPFRecord != NULL); } void DeleteHPFRecord( PHPF_RECORD pHPFRecord ) { PLIST_ENTRY pHead; PLIST_ENTRY pNext; PHPF_FILE_RECORD pHPFFileRecord; if (!pHPFRecord) return; RemoveEntryList(& pHPFRecord->Entry); pHead = & pHPFRecord->HPFReadListHead; pNext = pHead->Flink; while (pNext != pHead) { pHPFFileRecord = CONTAINING_RECORD(pNext, HPF_FILE_RECORD, Entry); pNext = pNext->Flink; RemoveEntryList(& pHPFFileRecord->Entry); free(pHPFFileRecord); } free(pHPFRecord); return; } VOID InitWorkloadRecord( PWORKLOAD_RECORD pWorkload ) { if (pWorkload == NULL) return; memset(pWorkload, 0, sizeof(WORKLOAD_RECORD)); InitializeListHead( &pWorkload->DiskListHead ); } VOID DeleteWorkloadRecord( PWORKLOAD_RECORD pWorkload ) { if (pWorkload == NULL) return; } PPROTO_PROCESS_RECORD AddProtoProcess( PFILE_RECORD pFile, PPROCESS_RECORD pProcess ) { PPROTO_PROCESS_RECORD pProto; if (pFile == NULL || pProcess == NULL) return NULL; pProto = malloc(sizeof(PROTO_PROCESS_RECORD)); if (pProto == NULL) { return NULL; } memset(pProto, 0, sizeof(PROTO_PROCESS_RECORD)); pProto->ProcessRecord = pProcess; InsertHeadList( &pFile->ProtoProcessListHead, &pProto->Entry ); return pProto; } PPROTO_PROCESS_RECORD FindProtoProcessRecord( PFILE_RECORD pFile, PPROCESS_RECORD pProcess ) { PLIST_ENTRY Next, Head; PPROTO_PROCESS_RECORD pProto; if (pFile == NULL || pProcess == NULL) return NULL; Head = &pFile->ProtoProcessListHead; Next = Head->Flink; while (Next != Head) { pProto = CONTAINING_RECORD(Next, PROTO_PROCESS_RECORD, Entry); if (pProcess == pProto->ProcessRecord) return pProto; Next = Next->Flink; } return (AddProtoProcess(pFile, pProcess)); } BOOLEAN AddProcess( ULONG ProcessId, PPROCESS_RECORD *ReturnedProcess ) { PPROCESS_RECORD Process; PMODULE_RECORD pModule = NULL; Process = malloc(sizeof(PROCESS_RECORD)); if (Process == NULL) { return FALSE; } InitProcessRecord( Process ); Process->PID = ProcessId; if (!AddModuleRecord(& pModule, 0, 0, L"other")) { free(Process); return FALSE; } pModule->pProcess = Process; EnterTracelibCritSection(); InsertHeadList( &CurrentSystem.ProcessListHead, &Process->Entry ); InsertHeadList(& Process->ModuleListHead, & pModule->Entry); LeaveTracelibCritSection(); *ReturnedProcess = Process; return TRUE; } BOOLEAN DeleteProcess( PPROCESS_RECORD Process ) { PLIST_ENTRY Next, Head; PTHREAD_RECORD Thread; PTDISK_RECORD Disk; PFILE_RECORD pFile; PMODULE_RECORD pModule; PHPF_RECORD pHPFRecord; if (Process == NULL) return FALSE; EnterTracelibCritSection(); RemoveEntryList( &Process->Entry ); LeaveTracelibCritSection(); Head = &Process->ThreadListHead; Next = Head->Flink; while (Next != Head) { Thread = CONTAINING_RECORD( Next, THREAD_RECORD, Entry ); Next = Next->Flink; DeleteThread( Thread ); } Head = &Process->DiskListHead; Next = Head->Flink; while (Next != Head) { Disk = CONTAINING_RECORD( Next, TDISK_RECORD, Entry ); Next = Next->Flink; DeleteDisk( Disk ); } Head = &Process->HPFListHead; Next = Head->Flink; while (Next != Head) { pHPFRecord = CONTAINING_RECORD(Next, HPF_RECORD, Entry); Next = Next->Flink; DeleteHPFRecord(pHPFRecord); } Head = &Process->FileListHead; Next = Head->Flink; while (Next != Head) { pFile = CONTAINING_RECORD( Next, FILE_RECORD, Entry ); Next = Next->Flink; RemoveEntryList( &pFile->Entry ); if (pFile->FileName != NULL) free(pFile->FileName); free(pFile); } Head = &Process->ModuleListHead; Next = Head->Flink; while (Next != Head) { pModule = CONTAINING_RECORD(Next, MODULE_RECORD, Entry); Next = Next->Flink; RemoveEntryList(& pModule->Entry); if(pModule->strModuleName) { free(pModule->strModuleName); } free(pModule); } if (Process->ImageName != NULL) free(Process->ImageName); if (Process->UserName != NULL) free(Process->UserName); free( Process ); return TRUE; } BOOLEAN AddThread( ULONG ThreadId, PEVENT_TRACE pEvent, PTHREAD_RECORD * ResultThread ) { PTHREAD_RECORD Thread; PEVENT_TRACE_HEADER pHeader = (PEVENT_TRACE_HEADER) & pEvent->Header; int i; Thread = malloc(sizeof(THREAD_RECORD)); if (Thread == NULL) { return FALSE; } InitThreadRecord(Thread); Thread->TimeStart = Thread->TimeEnd = (ULONGLONG) pHeader->TimeStamp.QuadPart; Thread->TID = ThreadId; Thread->ProcessorID = pEvent->ClientContext & 0x000000FF; i = (int)Thread->TID; i = i % THREAD_HASH_TABLESIZE; InsertHeadList(&CurrentSystem.ThreadHashList[i], &Thread->Entry); *ResultThread = Thread; return TRUE; } BOOLEAN DeleteThread( PTHREAD_RECORD Thread ) { PLIST_ENTRY pHead; PLIST_ENTRY pNext; PHPF_FILE_RECORD pHPFFileRecord; if (Thread == NULL) return FALSE; RemoveEntryList( &Thread->Entry ); DeleteTransList( &Thread->TransListHead, 0 ); pHead = & Thread->HPFReadListHead; pNext = pHead->Flink; while (pNext != pHead) { pHPFFileRecord = CONTAINING_RECORD(pNext, HPF_FILE_RECORD, Entry); pNext = pNext->Flink; RemoveEntryList(& pHPFFileRecord->Entry); free(pHPFFileRecord); } pHead = & Thread->HPFWriteListHead; pNext = pHead->Flink; while (pNext != pHead) { pHPFFileRecord = CONTAINING_RECORD(pNext, HPF_FILE_RECORD, Entry); pNext = pNext->Flink; RemoveEntryList(& pHPFFileRecord->Entry); free(pHPFFileRecord); } free( Thread ); return TRUE; } PTRANS_RECORD FindTransByList( PLIST_ENTRY Head, LPGUID pGuid, ULONG level ) { PLIST_ENTRY Next; PTRANS_RECORD pTrans = NULL; // Recursively look for the list that does // not contain a running guid // if (level <= MAX_TRANS_LEVEL && Head != NULL) { Next = Head->Flink; while (Next != Head) { pTrans = CONTAINING_RECORD(Next, TRANS_RECORD, Entry); if (pTrans->bStarted) { if ( (level == 0 || level == 1) && IsEqualGUID(pTrans->pGuid, pGuid)) { return pTrans; } else if (level > 0) { return FindTransByList(& pTrans->SubTransListHead, pGuid, level - 1); } } Next = Next->Flink; } } // Found the correct list; now find // the matching transaction // if (level == 0 && Head != NULL) { Next = Head->Flink; while (Next != Head) { pTrans = CONTAINING_RECORD(Next, TRANS_RECORD, Entry); if (IsEqualGUID( pTrans->pGuid, pGuid)) { return pTrans; } Next = Next->Flink; } // If not Found, go ahead and add it. // pTrans = malloc(sizeof(TRANS_RECORD)); if (pTrans == NULL) { return NULL; } InitTransRecord(pTrans); pTrans->pGuid = pGuid; InsertHeadList( Head, &pTrans->Entry ); } return pTrans; } PMOF_DATA FindMofData( PMOF_INFO pMofInfo, PWCHAR strSortKey ) { PLIST_ENTRY Next; PLIST_ENTRY Head; PMOF_DATA pMofData = NULL; if (pMofInfo == NULL) { return NULL; } Head = &pMofInfo->DataListHead; if (Head != NULL) { Next = Head->Flink; while (Next != Head) { pMofData = CONTAINING_RECORD(Next, MOF_DATA, Entry); if (strSortKey == NULL && pMofData->strSortKey == NULL) { return pMofData; } else if ( strSortKey != NULL && pMofData->strSortKey != NULL && !wcscmp(pMofData->strSortKey, strSortKey)) { return pMofData; } Next = Next->Flink; } // If not Found, go ahead and add it. // pMofData = (PMOF_DATA)malloc(sizeof(MOF_DATA)); if (pMofData == NULL) { return NULL; } InitMofData(pMofData); if (strSortKey != NULL) { pMofData->strSortKey = (PWCHAR) malloc((lstrlenW(strSortKey) + 1) * sizeof(WCHAR)); if (pMofData->strSortKey != NULL) { wcscpy(pMofData->strSortKey, strSortKey); } } InsertHeadList(Head, &pMofData->Entry); } return pMofData; } BOOLEAN DeleteTrans( PTRANS_RECORD Trans ) { if (Trans == NULL) return FALSE; RemoveEntryList( &Trans->Entry ); free( Trans ); return TRUE; } BOOLEAN DeleteTransList( PLIST_ENTRY Head, ULONG level ) { PLIST_ENTRY Next; PTRANS_RECORD pTrans; if( Head == NULL || level > MAX_TRANS_LEVEL ) return FALSE; Next = Head->Flink; while(Next != Head){ pTrans = CONTAINING_RECORD( Next, TRANS_RECORD, Entry ); Next = Next->Flink; DeleteTransList( &pTrans->SubTransListHead, level+1); DeleteTrans( pTrans ); } return TRUE; } PPROCESS_RECORD FindProcessById( ULONG Id, BOOLEAN CheckAlive ) { PLIST_ENTRY Next, Head; PPROCESS_RECORD Process=NULL; EnterTracelibCritSection(); Head = &CurrentSystem.ProcessListHead; Next = Head->Flink; while (Next != Head) { Process = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry ); if (Process->PID == Id) { LeaveTracelibCritSection(); if ((Process->DeadFlag) && (CheckAlive)) return NULL; else return Process; } Next = Next->Flink; } LeaveTracelibCritSection(); return NULL; } PTHREAD_RECORD FindGlobalThreadById( ULONG ThreadId, PEVENT_TRACE pEvent ) { PLIST_ENTRY Next, Head; PTHREAD_RECORD Thread; PEVENT_TRACE_HEADER pHeader = (PEVENT_TRACE_HEADER) & pEvent->Header; int i = (int)ThreadId; i = i % THREAD_HASH_TABLESIZE; Head = &CurrentSystem.ThreadHashList[i]; Next = Head->Flink; while (Next != Head) { Thread = CONTAINING_RECORD(Next, THREAD_RECORD, Entry); Next = Next->Flink; if (Thread->TID == ThreadId) { if (ThreadId == 0) { ULONG ProcessorId = pEvent->ClientContext & 0x000000FF; if (ProcessorId != Thread->ProcessorID) { continue; } } if (!Thread->DeadFlag) { return Thread; } else if ( Thread->TimeEnd == (ULONGLONG) pHeader->TimeStamp.QuadPart) { return Thread; } else { // The alive thead must be at the head of the list // otherwise bail // return NULL; } } } return NULL; } PWORKLOAD_RECORD FindWorkloadById( ULONG Id ) { PLIST_ENTRY Next, Head; PWORKLOAD_RECORD Workload = NULL; Head = &CurrentSystem.WorkloadListHead; Next = Head->Flink; while (Next != Head) { Workload = CONTAINING_RECORD( Next, WORKLOAD_RECORD, Entry ); if (Workload->ClassNumber == Id) { return Workload; } Next = Next->Flink; } return NULL; } BOOLEAN AddDisk( ULONG DiskNumber, PTDISK_RECORD *ReturnedDisk ) { PTDISK_RECORD Disk; Disk = malloc(sizeof(TDISK_RECORD)); if (Disk == NULL) { return FALSE; } InitDiskRecord(Disk, DiskNumber); Disk->DiskNumber = DiskNumber; InsertHeadList( &CurrentSystem.GlobalDiskListHead, &Disk->Entry ); *ReturnedDisk = Disk; return TRUE; } BOOLEAN DeleteDisk( PTDISK_RECORD Disk ) { PLIST_ENTRY Head, Next; PPROCESS_RECORD Process; PFILE_RECORD File; if (Disk == NULL) return FALSE; RemoveEntryList( &Disk->Entry ); if (Disk->DiskName != NULL) free(Disk->DiskName); Head = &Disk->ProcessListHead; Next = Head->Flink; while (Next != Head) { Process = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry ); Next = Next->Flink; DeleteProcess( Process ); } Head = &Disk->FileListHead; Next = Head->Flink; while (Next != Head) { File = CONTAINING_RECORD( Next, FILE_RECORD, Entry ); Next = Next->Flink; DeleteFileRecord( File ); } free( Disk ); return TRUE; } PTDISK_RECORD FindLocalDiskById( PLIST_ENTRY Head, ULONG Id ) { PLIST_ENTRY Next; PTDISK_RECORD Disk = NULL; if (Head == NULL) return NULL; Next = Head->Flink; while (Next != Head) { Disk = CONTAINING_RECORD( Next, TDISK_RECORD, Entry ); if (Disk->DiskNumber == Id) { return Disk; } Next = Next->Flink; } // If not Found, go ahead and add it. // Disk = malloc(sizeof(TDISK_RECORD)); if (Disk == NULL) { return FALSE; } InitDiskRecord(Disk, Id); Disk->DiskNumber = Id; InsertHeadList( Head, &Disk->Entry ); return Disk; } PTDISK_RECORD FindProcessDiskById( PPROCESS_RECORD pProcess, ULONG Id ) { PLIST_ENTRY Next, Head; PTDISK_RECORD Disk = NULL; if (pProcess == NULL) return NULL; Head = &pProcess->DiskListHead; Next = Head->Flink; while (Next != Head) { Disk = CONTAINING_RECORD( Next, TDISK_RECORD, Entry ); if (Disk->DiskNumber == Id) { return Disk; } Next = Next->Flink; } // If not Found, go ahead and add it. // Disk = malloc(sizeof(TDISK_RECORD)); if (Disk == NULL) { return FALSE; } InitDiskRecord(Disk, Id); Disk->DiskNumber = Id; InsertHeadList( &pProcess->DiskListHead, &Disk->Entry ); return Disk; } PPROCESS_RECORD FindDiskProcessById( PTDISK_RECORD pDisk, ULONG Id ) { PLIST_ENTRY Next, Head; PPROCESS_RECORD Process = NULL; PPROCESS_RECORD gProcess = NULL; if (pDisk == NULL) return NULL; Head = &pDisk->ProcessListHead; Next = Head->Flink; while (Next != Head) { Process = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry ); if (Process->PID == Id) { return Process; } Next = Next->Flink; } // If not Found, go ahead and add it. // Process = malloc(sizeof(PROCESS_RECORD)); if (Process == NULL) { return FALSE; } InitProcessRecord(Process); Process->PID = Id; // Find the global Process Record and copy the UserName and Image. // gProcess = FindProcessById(Id, FALSE); if (gProcess != NULL) { if ( ! IsEmpty( gProcess->UserName ) ) { ASSIGN_STRING( Process->UserName, gProcess->UserName ); if( NULL == Process->UserName ) { free(Process); return NULL; } } if (! IsEmpty( gProcess->ImageName ) ) { ASSIGN_STRING( Process->ImageName, gProcess->ImageName ); if (Process->UserName == NULL) { free(Process); return NULL; } } } InsertHeadList( &pDisk->ProcessListHead, &Process->Entry ); return Process; } PTDISK_RECORD FindGlobalDiskById( ULONG Id ) { PLIST_ENTRY Next, Head; PTDISK_RECORD Disk = NULL; Head = &CurrentSystem.GlobalDiskListHead; Next = Head->Flink; while (Next != Head) { Disk = CONTAINING_RECORD( Next, TDISK_RECORD, Entry ); if (Disk->DiskNumber == Id) { return Disk; } Next = Next->Flink; } return NULL; } VOID DeleteMofVersion( PMOF_VERSION pMofVersion, FILE* file ) { PLIST_ENTRY Next, Head; PITEM_DESC pMofItem; // // Traverse through the MOF_VERSION list and // delete each one // if (pMofVersion == NULL) return; if( NULL != file ){ fwprintf( file, L" %s (Type:%d Level:%d Version:%d)\n", pMofVersion->strType ? pMofVersion->strType : L"Default", pMofVersion->TypeIndex, pMofVersion->Level, pMofVersion->Version ); } Head = &pMofVersion->ItemHeader; Next = Head->Flink; while (Head != Next) { pMofItem = CONTAINING_RECORD(Next, ITEM_DESC, Entry); Next = Next->Flink; RemoveEntryList( &pMofItem->Entry ); if (pMofItem->strDescription != NULL){ if( NULL != file ){ fwprintf( file, L" %s\n", pMofItem->strDescription ); } free (pMofItem->strDescription); } free (pMofItem); } } VOID DeleteMofInfo( PMOF_INFO pMofInfo, FILE* f ) { PLIST_ENTRY Next, Head; PMOF_VERSION pMofVersion; // // Traverse through the MOF_VERSION list and // delete each one // if (pMofInfo == NULL){ return; } if( NULL != f ){ WCHAR buffer[MAXSTR]; fwprintf( f, L"%s\n", pMofInfo->strDescription ? pMofInfo->strDescription : CpdiGuidToString( buffer, &pMofInfo->Guid ) ); } Head = &pMofInfo->VersionHeader; Next = Head->Flink; while (Head != Next) { pMofVersion = CONTAINING_RECORD(Next, MOF_VERSION, Entry); Next = Next->Flink; RemoveEntryList( &pMofVersion->Entry ); DeleteMofVersion( pMofVersion, f ); } // // Delete any strings allocated for this structure // if (pMofInfo->strDescription){ free(pMofInfo->strDescription); } // // Finally delete the object // free(pMofInfo); } VOID Cleanup() { PTDISK_RECORD Disk; PTHREAD_RECORD Thread; PPROCESS_RECORD Process; PFILE_RECORD FileRec; PWORKLOAD_RECORD pWorkload; PMODULE_RECORD pModule; PMOF_INFO pMofInfo; PJOB_RECORD pJob; PLIST_ENTRY Next, Head; PLIST_ENTRY EventListHead; FILE* f = NULL; // Clean up the Global Disk List for now. // EventListHead = &CurrentSystem.EventListHead; Head = EventListHead; Next = Head->Flink; if( (TraceContext->Flags & TRACE_INTERPRET) && NULL != TraceContext->CompFileName ){ f = _wfopen( TraceContext->CompFileName, L"w" ); } while (Head != Next) { pMofInfo = CONTAINING_RECORD(Next, MOF_INFO, Entry); Next = Next->Flink; RemoveEntryList( &pMofInfo->Entry ); DeleteMofInfo(pMofInfo, f); } if( NULL != f ){ fclose( f ); f = NULL; } Head = &CurrentSystem.GlobalDiskListHead; Next = Head->Flink; while (Next != Head) { Disk = CONTAINING_RECORD( Next, TDISK_RECORD, Entry ); Next = Next->Flink; DeleteDisk( Disk ); } // Clean up the Global Thread List for now. // Head = &CurrentSystem.GlobalThreadListHead; Next = Head->Flink; while (Next != Head) { Thread = CONTAINING_RECORD( Next, THREAD_RECORD, Entry ); Next = Next->Flink; DeleteThread( Thread ); } Head = &CurrentSystem.ProcessListHead; Next = Head->Flink; while (Next != Head) { Process = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry ); Next = Next->Flink; DeleteProcess( Process ); } Head = &CurrentSystem.GlobalModuleListHead; Next = Head->Flink; while (Next != Head) { pModule = CONTAINING_RECORD(Next, MODULE_RECORD, Entry); Next = Next->Flink; RemoveEntryList(& pModule->Entry); if(pModule->strModuleName) { free(pModule->strModuleName); } free(pModule); } Head = &CurrentSystem.HotFileListHead; Next = Head->Flink; while (Next != Head) { FileRec = CONTAINING_RECORD( Next, FILE_RECORD, Entry ); Next = Next->Flink; DeleteFileRecord( FileRec ); } // Cleanup workload structures // Head = &CurrentSystem.WorkloadListHead; Next = Head->Flink; while (Next != Head) { pWorkload = CONTAINING_RECORD( Next, WORKLOAD_RECORD, Entry ); Next = Next->Flink; DeleteWorkloadRecord( pWorkload ); } // // Cleanup the Job List structures // Head = &CurrentSystem.JobListHead; Next = Head->Flink; while (Next != Head) { pJob = CONTAINING_RECORD( Next, JOB_RECORD, Entry ); Next = Next->Flink; DeleteJobRecord (pJob, FALSE); } } BOOLEAN AddFile( WCHAR* fileName, PFILE_RECORD *ReturnedFile ) { PFILE_RECORD fileRec; if (fileName == NULL) return FALSE; fileRec = malloc(sizeof(FILE_RECORD)); if (fileRec == NULL) { return FALSE; } InitFileRecord( fileRec ); fileRec->FileName = malloc( (lstrlenW(fileName)+ 1) * sizeof(WCHAR)); if (fileRec->FileName != NULL) { wcscpy(fileRec->FileName, fileName); } EnterTracelibCritSection(); InsertHeadList( &CurrentSystem.HotFileListHead, &fileRec->Entry ); LeaveTracelibCritSection(); *ReturnedFile = fileRec; return TRUE; } BOOLEAN DeleteFileRecord( PFILE_RECORD fileRec ) { PLIST_ENTRY Next, Head; PPROTO_PROCESS_RECORD pProto; if (fileRec == NULL) return FALSE; EnterTracelibCritSection(); RemoveEntryList( &fileRec->Entry ); LeaveTracelibCritSection(); if (fileRec->FileName != NULL) free(fileRec->FileName); Head = &fileRec->ProtoProcessListHead; Next = Head->Flink; while (Head != Next) { pProto = CONTAINING_RECORD( Next, PROTO_PROCESS_RECORD, Entry); Next = Next->Flink; RemoveEntryList( &pProto->Entry ); free(pProto); } free( fileRec ); return TRUE; } PFILE_RECORD FindFileRecordByName( WCHAR* fileName ) { PLIST_ENTRY Next, Head; PFILE_RECORD fileRec = NULL; if (fileName == NULL) return NULL; EnterTracelibCritSection(); Head = &CurrentSystem.HotFileListHead; Next = Head->Flink; while (Next != Head) { fileRec = CONTAINING_RECORD( Next, FILE_RECORD, Entry ); if (!wcscmp(fileName, fileRec->FileName)) { LeaveTracelibCritSection(); return fileRec; } Next = Next->Flink; } LeaveTracelibCritSection(); return NULL; } PFILE_RECORD FindFileInProcess( PPROCESS_RECORD pProcess, WCHAR* fileName ) { PLIST_ENTRY Next, Head; PFILE_RECORD fileRec = NULL; if (pProcess == NULL || fileName == NULL) return NULL; EnterTracelibCritSection(); Head = &pProcess->FileListHead; Next = Head->Flink; while (Next != Head) { fileRec = CONTAINING_RECORD( Next, FILE_RECORD, Entry ); if (!wcscmp(fileName, fileRec->FileName)) { //ReleaseMutex(CurrentSystem.HotFileListMutex); LeaveTracelibCritSection(); return fileRec; } Next = Next->Flink; } LeaveTracelibCritSection(); return NULL; } VOID AssignClass( PPROCESS_RECORD pProcess, PTHREAD_RECORD pThread ) { UNREFERENCED_PARAMETER(pProcess); pThread->ClassNumber = 1; // For the Time being make it single class. } VOID Classify() { // Assign Class to each Thread or Process. // PLIST_ENTRY Head, Next; PTHREAD_RECORD pThread; Head = &CurrentSystem.GlobalThreadListHead; Next = Head->Flink; while (Next != Head) { pThread = CONTAINING_RECORD( Next, THREAD_RECORD, Entry ); AssignClass(NULL, pThread); Aggregate(pThread); Next = Next->Flink; } } // Given the number of classes this routine // creates and initializes the workload object // VOID InitClass() { PWORKLOAD_RECORD pWorkload; ULONG nclass; ULONG i; // Create the Class records here. // nclass = 1; CurrentSystem.NumberOfWorkloads = 1; for (i = 1; i <= nclass; i++) { pWorkload = malloc(sizeof(WORKLOAD_RECORD)); if (pWorkload == NULL) { return; } InitWorkloadRecord( pWorkload ); pWorkload->ClassNumber = i; InsertHeadList( &CurrentSystem.WorkloadListHead, &pWorkload->Entry ); } } PTDISK_RECORD FindDiskInList( IN PLIST_ENTRY Head, IN ULONG Id ) { PLIST_ENTRY Next; PTDISK_RECORD pDisk = NULL; if (Head != NULL) { Next = Head->Flink; while (Next != Head) { pDisk = CONTAINING_RECORD ( Next, TDISK_RECORD, Entry ); if (pDisk->DiskNumber == Id) { return pDisk; } Next = Next->Flink; } pDisk = malloc(sizeof(TDISK_RECORD)); if (pDisk == NULL) { return NULL; } InitDiskRecord( pDisk, Id ); InsertHeadList( Head, &pDisk->Entry ); } return pDisk; } VOID Aggregate( IN PTHREAD_RECORD pThread ) { PWORKLOAD_RECORD pWorkload; PTDISK_RECORD pDisk, pClassDisk; PLIST_ENTRY Next, Head; // Aggregate the metrics over each class. // if ((pWorkload = FindWorkloadById(pThread->ClassNumber)) != NULL) { pWorkload->UserCPU += (pThread->UCPUEnd - pThread->UCPUStart) * CurrentSystem.TimerResolution; pWorkload->KernelCPU += (pThread->KCPUEnd - pThread->KCPUStart) * CurrentSystem.TimerResolution; // // Walk through the Thread Disk records and aggregate them // to the class Head = &pThread->DiskListHead; Next = Head->Flink; while (Next != Head) { pDisk = CONTAINING_RECORD( Next, TDISK_RECORD, Entry ); Next = Next->Flink; pClassDisk = FindDiskInList(&pWorkload->DiskListHead, pDisk->DiskNumber) ; if (pClassDisk != NULL) { pClassDisk->ReadCount += pDisk->ReadCount; pClassDisk->WriteCount += pDisk->WriteCount; pClassDisk->ReadSize += (pDisk->ReadCount * pDisk->ReadSize); pClassDisk->WriteSize += (pDisk->WriteCount * pDisk->WriteSize); pWorkload->ReadCount += pDisk->ReadCount; } } } } ULONGLONG CalculateProcessLifeTime( PPROCESS_RECORD pProcess ) { BOOLEAN fFirst = TRUE; ULONGLONG TimeStart = 0; ULONGLONG TimeEnd = 0; PLIST_ENTRY pHead = &pProcess->ThreadListHead; PLIST_ENTRY pNext = pHead->Flink; PTHREAD_RECORD pThread; while (pNext != pHead) { pThread = CONTAINING_RECORD(pNext, THREAD_RECORD, Entry); pNext = pNext->Flink; if (fFirst) { TimeStart = pThread->TimeStart; TimeEnd = pThread->TimeEnd; fFirst = FALSE; } else if (pThread->TimeStart < TimeStart) { TimeStart = pThread->TimeStart; } else if (pThread->TimeEnd > TimeEnd) { TimeEnd = pThread->TimeEnd; } } return (TimeEnd - TimeStart); } ULONG CalculateProcessKCPU( PPROCESS_RECORD pProcess ) { ULONG KCPUTotal = 0; ULONG KCPUMissing = 0; PLIST_ENTRY pHead = &pProcess->ThreadListHead; PLIST_ENTRY pNext = pHead->Flink; PTHREAD_RECORD pThread; while (pNext != pHead) { pThread = CONTAINING_RECORD(pNext, THREAD_RECORD, Entry); pNext = pNext->Flink; if (pThread->KCPUEnd > pThread->KCPUStart) { if ((pProcess->PID != 0) || ((pProcess->PID == 0) && (pThread->TID == 0)) ){ KCPUTotal += pThread->KCPUEnd - pThread->KCPUStart; } else { KCPUMissing += pThread->KCPUEnd - pThread->KCPUStart; } } } return (ULONG) (KCPUTotal * CurrentSystem.TimerResolution); } ULONG CalculateProcessUCPU( PPROCESS_RECORD pProcess ) { ULONG UCPUTotal = 0; ULONG UCPUMissing = 0; PLIST_ENTRY pHead = &pProcess->ThreadListHead; PLIST_ENTRY pNext = pHead->Flink; PTHREAD_RECORD pThread; while (pNext != pHead) { pThread = CONTAINING_RECORD(pNext, THREAD_RECORD, Entry); pNext = pNext->Flink; if (pThread->UCPUEnd > pThread->UCPUStart) { if ((pProcess->PID != 0) || ((pProcess->PID == 0) && (pThread->TID == 0)) ) { UCPUTotal += pThread->UCPUEnd - pThread->UCPUStart; } else { UCPUMissing += pThread->UCPUEnd - pThread->UCPUStart; } } } return (ULONG) (UCPUTotal * CurrentSystem.TimerResolution); } PJOB_RECORD FindJobRecord( ULONG JobId ) { PLIST_ENTRY Head, Next; PJOB_RECORD pJob; EnterTracelibCritSection(); Head = &CurrentSystem.JobListHead; Next = Head->Flink; while (Next != Head) { pJob = CONTAINING_RECORD ( Next, JOB_RECORD, Entry ); if (pJob->JobId == JobId) { LeaveTracelibCritSection(); return pJob; } Next = Next->Flink; } LeaveTracelibCritSection(); return NULL; } // // A New Job with a JobId has been found. This routine will create a // new job record to track it through various threads in the system // PJOB_RECORD AddJobRecord( ULONG JobId ) { PJOB_RECORD pJob; pJob = malloc(sizeof(JOB_RECORD)); if (pJob == NULL) { SetLastError( ERROR_OUTOFMEMORY); return NULL; } RtlZeroMemory(pJob, sizeof(JOB_RECORD)); pJob->JobId = JobId; EnterTracelibCritSection(); InsertHeadList( &CurrentSystem.JobListHead, &pJob->Entry ); LeaveTracelibCritSection(); return pJob; } // // Deletes a Job record with the JobId. Before deleting the contents // of the job record is dumped to a temp file for later reporting. // ULONG DeleteJobRecord( PJOB_RECORD pJob, ULONG bSave ) { if (pJob == NULL) return ERROR_INVALID_PARAMETER; // // Print the Contents of pJob to file. // // If the -spooler option isn't given to the reducer this fprintf causes the // program to crash. Maybe TRACE_SPOOLER should alway be set. if (CurrentSystem.TempFile != NULL) { fprintf(CurrentSystem.TempFile, "%d, %d, %d, %d, %I64u, %I64u, %I64u, %I64u, %d, %d, %d, %d, %d, %hd, %d, %hd, %hd, %hd, %hd, %hd, %hd, %d\n", pJob->JobId, pJob->KCPUTime, pJob->UCPUTime, pJob->ReadIO, pJob->StartTime, pJob->EndTime, (pJob->ResponseTime - pJob->PauseTime), pJob->PrintJobTime, pJob->WriteIO, pJob->DataType, pJob->JobSize, pJob->Pages, pJob->PagesPerSide, pJob->FilesOpened, pJob->GdiJobSize, pJob->Color, pJob->XRes, pJob->YRes, pJob->Quality, pJob->Copies, pJob->TTOption, pJob->NumberOfThreads); } EnterTracelibCritSection(); RemoveEntryList( &pJob->Entry ); LeaveTracelibCritSection(); free (pJob); return ERROR_SUCCESS; }