internal unsafe CategorySample(byte[] data, CategoryEntry entry, PerformanceCounterLib library) { this.entry = entry; this.library = library; int categoryIndex = entry.NameIndex; NativeMethods.PERF_DATA_BLOCK dataBlock = new NativeMethods.PERF_DATA_BLOCK(); fixed (byte* dataPtr = data) { IntPtr dataRef = new IntPtr((void*) dataPtr); Marshal.PtrToStructure(dataRef, dataBlock); this.SystemFrequency = dataBlock.PerfFreq; this.TimeStamp = dataBlock.PerfTime; this.TimeStamp100nSec = dataBlock.PerfTime100nSec; dataRef = (IntPtr)((long)dataRef + dataBlock.HeaderLength); int numPerfObjects = dataBlock.NumObjectTypes; if (numPerfObjects == 0) { this.CounterTable = new Hashtable(); this.InstanceNameTable = new Hashtable(StringComparer.OrdinalIgnoreCase); return; } //Need to find the right category, GetPerformanceData might return //several of them. NativeMethods.PERF_OBJECT_TYPE perfObject = null; bool foundCategory = false; for (int index = 0; index < numPerfObjects; index++) { perfObject = new NativeMethods.PERF_OBJECT_TYPE(); Marshal.PtrToStructure(dataRef, perfObject); if (perfObject.ObjectNameTitleIndex == categoryIndex) { foundCategory = true; break; } dataRef = (IntPtr)((long)dataRef + perfObject.TotalByteLength); } if (!foundCategory) throw new InvalidOperationException(SR.GetString(SR.CantReadCategoryIndex, categoryIndex.ToString(CultureInfo.CurrentCulture))); this.CounterFrequency = perfObject.PerfFreq; this.CounterTimeStamp = perfObject.PerfTime; int counterNumber = perfObject.NumCounters; int instanceNumber = perfObject.NumInstances; if (instanceNumber == -1) IsMultiInstance = false; else IsMultiInstance = true; // Move pointer forward to end of PERF_OBJECT_TYPE dataRef = (IntPtr)((long)dataRef + perfObject.HeaderLength); CounterDefinitionSample[] samples = new CounterDefinitionSample[counterNumber]; this.CounterTable = new Hashtable(counterNumber); for (int index = 0; index < samples.Length; ++ index) { NativeMethods.PERF_COUNTER_DEFINITION perfCounter = new NativeMethods.PERF_COUNTER_DEFINITION(); Marshal.PtrToStructure(dataRef, perfCounter); samples[index] = new CounterDefinitionSample(perfCounter, this, instanceNumber); dataRef = (IntPtr)((long)dataRef + perfCounter.ByteLength); int currentSampleType = samples[index].CounterType; if (!PerformanceCounterLib.IsBaseCounter(currentSampleType)) { // We'll put only non-base counters in the table. if (currentSampleType != NativeMethods.PERF_COUNTER_NODATA) this.CounterTable[samples[index].NameIndex] = samples[index]; } else { // it's a base counter, try to hook it up to the main counter. Debug.Assert(index > 0, "Index > 0 because base counters should never be at index 0"); if (index > 0) samples[index-1].BaseCounterDefinitionSample = samples[index]; } } // now set up the InstanceNameTable. if (!IsMultiInstance) { this.InstanceNameTable = new Hashtable(1, StringComparer.OrdinalIgnoreCase); this.InstanceNameTable[PerformanceCounterLib.SingleInstanceName] = 0; for (int index = 0; index < samples.Length; ++ index) { samples[index].SetInstanceValue(0, dataRef); } } else { string[] parentInstanceNames = null; this.InstanceNameTable = new Hashtable(instanceNumber, StringComparer.OrdinalIgnoreCase); for (int i = 0; i < instanceNumber; i++) { NativeMethods.PERF_INSTANCE_DEFINITION perfInstance = new NativeMethods.PERF_INSTANCE_DEFINITION(); Marshal.PtrToStructure(dataRef, perfInstance); if (perfInstance.ParentObjectTitleIndex > 0 && parentInstanceNames == null) parentInstanceNames = GetInstanceNamesFromIndex(perfInstance.ParentObjectTitleIndex); string instanceName; if (parentInstanceNames != null && perfInstance.ParentObjectInstance >= 0 && perfInstance.ParentObjectInstance < parentInstanceNames.Length - 1) instanceName = parentInstanceNames[perfInstance.ParentObjectInstance] + "/" + Marshal.PtrToStringUni((IntPtr)((long)dataRef + perfInstance.NameOffset)); else instanceName = Marshal.PtrToStringUni((IntPtr)((long)dataRef + perfInstance.NameOffset)); //In some cases instance names are not unique (Process), same as perfmon //generate a unique name. string newInstanceName = instanceName; int newInstanceNumber = 1; while (true) { if (!this.InstanceNameTable.ContainsKey(newInstanceName)) { this.InstanceNameTable[newInstanceName] = i; break; } else { newInstanceName = instanceName + "#" + newInstanceNumber.ToString(CultureInfo.InvariantCulture); ++ newInstanceNumber; } } dataRef = (IntPtr)((long)dataRef + perfInstance.ByteLength); for (int index = 0; index < samples.Length; ++ index) samples[index].SetInstanceValue(i, dataRef); dataRef = (IntPtr)((long)dataRef + Marshal.ReadInt32(dataRef)); } } } }
internal unsafe string[] GetInstanceNamesFromIndex(int categoryIndex) { byte[] data = library.GetPerformanceData(categoryIndex.ToString(CultureInfo.InvariantCulture)); fixed (byte* dataPtr = data) { IntPtr dataRef = new IntPtr((void*) dataPtr); NativeMethods.PERF_DATA_BLOCK dataBlock = new NativeMethods.PERF_DATA_BLOCK(); Marshal.PtrToStructure(dataRef, dataBlock); dataRef = (IntPtr)((long)dataRef + dataBlock.HeaderLength); int numPerfObjects = dataBlock.NumObjectTypes; NativeMethods.PERF_OBJECT_TYPE perfObject = null; bool foundCategory = false; for (int index = 0; index < numPerfObjects; index++) { perfObject = new NativeMethods.PERF_OBJECT_TYPE(); Marshal.PtrToStructure(dataRef, perfObject); if (perfObject.ObjectNameTitleIndex == categoryIndex) { foundCategory = true; break; } dataRef = (IntPtr)((long)dataRef + perfObject.TotalByteLength); } if (!foundCategory) return new string[0]; int counterNumber = perfObject.NumCounters; int instanceNumber = perfObject.NumInstances; dataRef = (IntPtr)((long)dataRef + perfObject.HeaderLength); if (instanceNumber == -1) return new string[0]; CounterDefinitionSample[] samples = new CounterDefinitionSample[counterNumber]; for (int index = 0; index < samples.Length; ++ index) { NativeMethods.PERF_COUNTER_DEFINITION perfCounter = new NativeMethods.PERF_COUNTER_DEFINITION(); Marshal.PtrToStructure(dataRef, perfCounter); dataRef = (IntPtr)((long)dataRef + perfCounter.ByteLength); } string[] instanceNames = new string[instanceNumber]; for (int i = 0; i < instanceNumber; i++) { NativeMethods.PERF_INSTANCE_DEFINITION perfInstance = new NativeMethods.PERF_INSTANCE_DEFINITION(); Marshal.PtrToStructure(dataRef, perfInstance); instanceNames[i] = Marshal.PtrToStringUni((IntPtr)((long)dataRef + perfInstance.NameOffset)); dataRef = (IntPtr)((long)dataRef + perfInstance.ByteLength); dataRef = (IntPtr)((long)dataRef + Marshal.ReadInt32(dataRef)); } return instanceNames; } }
static ProcessInfo[] GetProcessInfos(PerformanceCounterLib library, int processIndex, int threadIndex, byte[] data) { Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos()"); Hashtable processInfos = new Hashtable(); ArrayList threadInfos = new ArrayList(); GCHandle dataHandle = new GCHandle(); try { dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); IntPtr dataBlockPtr = dataHandle.AddrOfPinnedObject(); NativeMethods.PERF_DATA_BLOCK dataBlock = new NativeMethods.PERF_DATA_BLOCK(); Marshal.PtrToStructure(dataBlockPtr, dataBlock); IntPtr typePtr = (IntPtr)((long)dataBlockPtr + dataBlock.HeaderLength); NativeMethods.PERF_INSTANCE_DEFINITION instance = new NativeMethods.PERF_INSTANCE_DEFINITION(); NativeMethods.PERF_COUNTER_BLOCK counterBlock = new NativeMethods.PERF_COUNTER_BLOCK(); for (int i = 0; i < dataBlock.NumObjectTypes; i++) { NativeMethods.PERF_OBJECT_TYPE type = new NativeMethods.PERF_OBJECT_TYPE(); Marshal.PtrToStructure(typePtr, type); IntPtr instancePtr = (IntPtr)((long)typePtr + type.DefinitionLength); IntPtr counterPtr = (IntPtr)((long)typePtr + type.HeaderLength); ArrayList counterList = new ArrayList(); for (int j = 0; j < type.NumCounters; j++) { NativeMethods.PERF_COUNTER_DEFINITION counter = new NativeMethods.PERF_COUNTER_DEFINITION(); Marshal.PtrToStructure(counterPtr, counter); string counterName = library.GetCounterName(counter.CounterNameTitleIndex); if (type.ObjectNameTitleIndex == processIndex) counter.CounterNameTitlePtr = (int)GetValueId(counterName); else if (type.ObjectNameTitleIndex == threadIndex) counter.CounterNameTitlePtr = (int)GetValueId(counterName); counterList.Add(counter); counterPtr = (IntPtr)((long)counterPtr + counter.ByteLength); } NativeMethods.PERF_COUNTER_DEFINITION[] counters = new NativeMethods.PERF_COUNTER_DEFINITION[counterList.Count]; counterList.CopyTo(counters, 0); for (int j = 0; j < type.NumInstances; j++) { Marshal.PtrToStructure(instancePtr, instance); IntPtr namePtr = (IntPtr)((long)instancePtr + instance.NameOffset); string instanceName = Marshal.PtrToStringUni(namePtr); if (instanceName.Equals("_Total")) continue; IntPtr counterBlockPtr = (IntPtr)((long)instancePtr + instance.ByteLength); Marshal.PtrToStructure(counterBlockPtr, counterBlock); if (type.ObjectNameTitleIndex == processIndex) { ProcessInfo processInfo = GetProcessInfo(type, (IntPtr)((long)instancePtr + instance.ByteLength), counters); if (processInfo.processId == 0 && string.Compare(instanceName, "Idle", StringComparison.OrdinalIgnoreCase) != 0) { // Sometimes we'll get a process structure that is not completely filled in. // We can catch some of these by looking for non-"idle" processes that have id 0 // and ignoring those. Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos() - found a non-idle process with id 0; ignoring."); } else { if (processInfos[processInfo.processId] != null) { // We've found two entries in the perfcounters that claim to be the // same process. We throw an exception. Is this really going to be // helpfull to the user? Should we just ignore? Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos() - found a duplicate process id"); } else { // the performance counters keep a 15 character prefix of the exe name, and then delete the ".exe", // if it's in the first 15. The problem is that sometimes that will leave us with part of ".exe" // at the end. If instanceName ends in ".", ".e", or ".ex" we remove it. string processName = instanceName; if (processName.Length == 15) { if (instanceName.EndsWith(".", StringComparison.Ordinal )) processName = instanceName.Substring(0, 14); else if (instanceName.EndsWith(".e", StringComparison.Ordinal )) processName = instanceName.Substring(0, 13); else if (instanceName.EndsWith(".ex", StringComparison.Ordinal)) processName = instanceName.Substring(0, 12); } processInfo.processName = processName; processInfos.Add(processInfo.processId, processInfo); } } } else if (type.ObjectNameTitleIndex == threadIndex) { ThreadInfo threadInfo = GetThreadInfo(type, (IntPtr)((long)instancePtr + instance.ByteLength), counters); if (threadInfo.threadId != 0) threadInfos.Add(threadInfo); } instancePtr = (IntPtr)((long)instancePtr + instance.ByteLength + counterBlock.ByteLength); } typePtr = (IntPtr)((long)typePtr + type.TotalByteLength); } } finally { if (dataHandle.IsAllocated) dataHandle.Free(); } for (int i = 0; i < threadInfos.Count; i++) { ThreadInfo threadInfo = (ThreadInfo)threadInfos[i]; ProcessInfo processInfo = (ProcessInfo)processInfos[threadInfo.processId]; if (processInfo != null) { processInfo.threadInfoList.Add(threadInfo); } } ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count]; processInfos.Values.CopyTo(temp, 0); return temp; }