잊지 않겠습니다.

'Performance Counter'에 해당되는 글 1건

  1. 2009.07.29 Hyper-V Virtual Machine Performance Counter
Hyper-V 에서 Network Usage와 Process Usage를 얻어내기 위해서 WMI 뒤지기 삽질. -_-

이번에 WMI를 보면서 많은 생각이 든 것이, MS가 참 대단하다는 생각이 든다. 정말 여러 데이터들을 잘 모아뒀다는 그런 느낌이라고 해야지 될까. 
먼저 Performance Counter에 사용되는 WMI 들은 Win32_PerfFormattedData_, Win32_PerfRawData_ 두가지로 나뉘어진다. 이 두개의 데이터의 차이는 좀 더 알아보기 쉽게 변형된 데이터와 Raw Data의 차이를 가지고 있다. 예를 들어 Network Usage의 경우 FormattedData의 경우에는 Bytes/sec의 정보가 나온다. 그렇지만 Raw Data는 Bytes의 누적값으로 표현이 된다. 이렇게 약간약간 다른 값들이 있기 때문에, 좀 더 세밀하게 볼 필요성이 있다. 

뭐.. 바로 본론으로 들어가면, 필요한 WMI 정보와 WMI를 얻어내는데 필요한 Helper Class를 먼저 제작해줬다. 


01.public class WmiHelper
02.{
03.    private readonly ConnectionOptions _connectionOptions;
04.    public WmiHelper()
05.    {
06.        _connectionOptions = new ConnectionOptions()
07.                                {
08.                                    Impersonation = ImpersonationLevel.Impersonate,
09.                                    Username = Configure.UserName,
10.                                    Password = Configure.Password,
11.                                    Authentication = AuthenticationLevel.Default,
12.                                    EnablePrivileges = true
13. 
14.                                };
15.    }
16. 
17.    protected ManagementObject GetManagementSingleObject(string wmiQuery, string wmiNamespace)
18.    {
19.        ManagementScope scope = new ManagementScope(wmiNamespace, _connectionOptions);
20.        try
21.        {
22.            scope.Connect();
23.            ObjectQuery query = new ObjectQuery(wmiQuery);
24.            using(ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
25.            {
26.                ManagementObjectCollection queryCollection = searcher.Get();
27.                return GetFirsManagementObject(queryCollection);
28.            }
29.        }
30.        catch(Exception ex)
31.        {
32.            Console.WriteLine(ex.Message);
33.            return null;
34.        }
35.    }
36. 
37.    protected ManagementObjectCollection GetManagementCollection(string wmiQuery, string wmiNamespace)
38.    {
39.        ManagementScope scope = new ManagementScope(wmiNamespace, _connectionOptions);
40.        try
41.        {
42.            scope.Connect();
43.            ObjectQuery query = new ObjectQuery(wmiQuery);
44.            using(ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
45.            {
46.                ManagementObjectCollection queryCollection = searcher.Get();
47.                return queryCollection;
48.            }
49.        }
50.        catch(Exception ex)
51.        {
52.            Console.WriteLine(ex.Message);
53.            return null;
54.        }
55.    }
56. 
57.    protected ManagementObject GetFirsManagementObject(ManagementObjectCollection managementObjectCollection)
58.    {
59.        if(managementObjectCollection.Count == 0)
60.        {
61.            return null;
62.        }
63.        else
64.        {
65.            var enumerator = managementObjectCollection.GetEnumerator();
66.            enumerator.MoveNext();
67.            return (ManagementObject)enumerator.Current;
68.        }
69.    }
70.}
WmiHelper는 Connection과 WMI Query를 Execute, 얻어진 ManagementObject와 ObjectCollection 얻어오는 일을 담당한다.
이제 Hyper-V의 Network Usage와 CPU Usage를 얻어오는 PerformanceCounter Class의 내용은 다음과 같다. 

001.public class VirtualMachinePerformanceCounter : WmiHelper
002.{
003.    //public long NetworkReadBytes { get; private set; }
004.    //public long NetworkWriteBytes { get; private set; }
005.    //public double CpuUsage { get; private set; }
006. 
007.    private readonly string _vmName;
008.    private readonly string _hostName;
009. 
010.    public VirtualMachinePerformanceCounter(string vmName, string hostName)
011.    {
012.        _vmName = vmName;
013.        _hostName = hostName;
014.    }
015. 
016.    public NetworkBandwidth MonitorNetworkBandwidth()
017.    {
018.        string wmiNamespace = string.Format("\\\\{0}\\Root\\cimv2", _hostName);
019.        string vmComputerName = GetVirtualComputerSystemGuidName();
020.        string wmiQuery =
021.            string.Format(
022.                "SELECT * FROM Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter WHERE Name like \"%_{0}--%\"",
023.                vmComputerName);
024.  
025.        ManagementObject managementObject = GetManagementSingleObject(wmiQuery, wmiNamespace);
026.        if(managementObject != null)
027.        {
028.            string recevedBytesString = managementObject["BytesReceivedPersec"].ToString();
029.            string sentBytesString = managementObject["BytesSentPersec"].ToString();
030.            string totalBytesString = managementObject["BytesPersec"].ToString();
031. 
032.            NetworkBandwidth networkBandwidth = new NetworkBandwidth(long.Parse(totalBytesString),
033.                                                         long.Parse(recevedBytesString), long.Parse(sentBytesString));
034.            Console.WriteLine("{0}\t{1}\t{2}", totalBytesString, recevedBytesString, sentBytesString);
035.            return networkBandwidth;
036.        }
037.        else
038.        {
039.            return NetworkBandwidth.Empty;
040.        }
041.    }
042. 
043. 
044.    public CpuUsage MonitorCpuUsage()
045.    {
046.        /*
047.        Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor
048.        Frequency_PerfTime
049.        PercentGuestRunTime
050.        Timestamp_PerfTime
051.        */
052.        string wmiNamespace = string.Format("\\\\{0}\\Root\\cimv2", _hostName);
053.        string wmiQuery = string.Format("SELECT Frequency_PerfTime,PercentGuestRunTime, Timestamp_PerfTime " +
054.                                        "FROM Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor " +
055.                                        "WHERE Name like \"{0}:%\"", _vmName);
056. 
057.        ManagementObjectCollection preManagementObjects = GetManagementCollection(wmiQuery, wmiNamespace);
058.         
059.        int logicalProcessCount = preManagementObjects.Count;
060. 
061.        if(logicalProcessCount == 0)
062.        {
063.            return CpuUsage.Empty;
064.        }
065.        else
066.        {
067.            ManagementObject m1 = GetFirsManagementObject(preManagementObjects);
068.            long frequencyPerfTime = long.Parse(m1["Frequency_PerfTime"].ToString());
069. 
070.            long percentGuestRunTime1 = long.Parse(m1["PercentGuestRunTime"].ToString());
071.            long timestampPerfTime1 = long.Parse(m1["Timestamp_PerfTime"].ToString());
072. 
073.            System.Threading.Thread.Sleep(1000);
074. 
075.            ManagementObject m2 = GetManagementSingleObject(wmiQuery, wmiNamespace);
076.            long percentGuestRunTime2 = long.Parse(m2["PercentGuestRunTime"].ToString());
077.            long timestampPerfTime2 = long.Parse(m2["Timestamp_PerfTime"].ToString());
078. 
079.            CpuUsage usage = new CpuUsage()
080.                                 {
081.                                     LogicalProcessCount = logicalProcessCount,
082.                                     FrequencyPerfTime = frequencyPerfTime,
083.                                     GuestRunTime1 = percentGuestRunTime1,
084.                                     GuestRunTime2 = percentGuestRunTime2,
085.                                     TimeStampPerTime1 = timestampPerfTime1,
086.                                     TimeStampPerTime2 = timestampPerfTime2
087.                                 };
088. 
089.            return usage;
090.        }
091.    }
092. 
093.    private string GetVirtualComputerSystemGuidName()
094.    {
095.        string wmiNamespace = string.Format("\\\\{0}\\Root\\virtualization", _hostName);
096.        string wmiQuery = string.Format("SELECT * FROM Msvm_ComputerSystem WHERE elementname = \"{0}\"", _vmName);
097. 
098.        ManagementObject managementObject = GetManagementSingleObject(wmiQuery, wmiNamespace);
099.        return (string)managementObject["Name"];
100.    }
101.}
간단히 코드 설명을 한다면, 

Network Usage는 Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter에서 얻어지는 값을 이용하면 된다. 
VM과 연관을 찾기 위해서는 root\virtualization에서 VirtualComputerSystem의 Name 값을 이용해서 like 검색을 하면 된다.

CPU Usage의 경우에는 http://blogs.msdn.com/tvoellm/archive/2008/07/14/how-to-get-processor-utilization-for-hyper-v-via-wmi.aspx를
참고.

* WmiHelper를 상속받는 것이 아닌, 아무래도 생성해서 Instance를 private로 들고 있는 것이 더 나았을 것 같다. 아무리 봐도.;
Posted by Y2K
,