WMI: Improving your WMI application performance in fan-out scenario
One of the powerful capabilities in WMI is allowing authenticated users and applications to perform management tasks on a remote computer through DCOM. This is particularly useful in the fan-out scenario where developers can write applications to monitor a group of workstations and servers from a single machine using WMI.
For example, a developer who wants to write an application to collect the free disk space on all computers in an organization can use one of the WMI client APIs – WMI COM API, System.Management in .NET, WMI Scripting API, or WMI PowerShell cmdlets – to collect the information from all the machines. Among these four client APIs, WMI COM API offers developers the greatest control of the way a WMI remote connection is established and closed.
In this blog, I will talk about three different ways of connecting to a remote machine using WMI to perform multiple WMI operations, and their performance differences. Suppose I have ten machines and I need to periodically poll the status of the hard drives on each machine using WMI. I can choose one of the following approaches to write my application:
1) Connecting using Explicit Credential
My application calls IWbemLocator::ConnectServer method to establish a DCOM connection with each remote machine using an explicit credential I specified. The credential could be the local administrator of the remote machine. The application polls the hard drive status through a WMI provider and then closes the connection. The connect-poll-close process is repeated continuously to get the fresh status from all remote machines.
2) Connecting using Default Credential
Like (1) above, my application connects to each remote machine, polls the hard drive status through a WMI provider, and closes the connection. The only difference in this approach is that no explicit credentials are specified when calling the ConnectServer method. The application uses the default credential, which could be a domain user that has administrative access to the remote machines.
3) Reusing WMI Connection
My application calls the ConnectServer method to connect to the remote machines either with explicit credential or default credential specified, and then it polls the status of the hard drives through a WMI provider. Instead of closing the connection, my application keeps it open for subsequent polls by holding on to the reference to the IWbemServices object.
Let’s find out what the differences are for these three scenarios in terms of WMI throughput [1]. I set up ten machines with a variety of Windows OS installed. Each machine is joined to the same domain and has the same hardware configuration [2]. Instead of polling the hard drive status, my WMI application repeatedly connects to each of the ten machines, and performs the same WMI object query operation on a test WMI provider. To minimize the variation due to the provider processing time, my test WMI provider always returns the same set of results for the query I use on any given machine. Figure 1 shows the average throughput of the client-side OS platforms on which my WMI application is run.
Figure 1: Fan out Remoting Throughput using WMI
Of course the absolute values of the throughput may vary depending on different factors, such as the payload of the query results, the network latency, the processor speed, etc. However, there are a couple of interesting observations in this fan-out experiment:
a) Of all three client-side OS platforms I tested, if my application uses the same WMI connection throughout the life time of the WMI operations (which is approach 3 mentioned above), the throughput measured is almost 3 times greater than if the application opens and closes the connection for each WMI operation. This is due to fewer authentication requests that the client-side OS needs to process.
b) On Windows Server 2008 only, my WMI application using default credential has throughput nearly 6 times higher compared to my application using explicit credential. Moreover, the lsass.exe process consumes considerable CPU cycles when connecting to the remote machines using explicit credential. The performance delta is partly due to a security change made in Windows Vista and Windows Server 2008.
c) On Windows Server 2008 with explicit credential, I am able to improve the throughput of my application to the level comparable to the throughput on the other two client-side OS platforms by changing the way I pass the explicit credential to my test code. Here is the pseudo-code of my change:
1. Call LogonUser function with an explicit credential
2. Call ImpersonateLoggedOnUser function with the token returned in (1)
3. Call ConnectServer to connect to remote machines using default credential
4. Perform the WMI object query
5. Close the connection
Best of all, the change keeps the lsass.exe process running like cool mint.
Andy Cheung [MSFT]
PS: Thanks to Vivek and Sunil for the help on this post.
[1] The unit of measurement for throughput I use in this blog is operation per second. An operation consists of connecting to a remote server, querying WMI objects, parsing the result set, and closing the connection. In the “Reusing WMI Connection” approach, the cost of establishing and closing a connection is incurred only once.
[2] All machines are Pentium 4, 2.4GHz, 1GB RAM. The network is Gigabit. All client-side OS platforms are 64-bit.
Comments
Anonymous
June 30, 2009
Is there a way to "hold" the connection when using VBscript and/or PowerShell? Thx...Anonymous
June 30, 2009
In VBScript, you can reuse the SWbemLocator object to achieve higher performance when connecting to the same remote WMI namespace. If you are using WMI Powershell Cmdlets, you cannot "hold" the connection as WMI Cmdlets do not expose any references to the connection. In the managed code world, you can reuse the ManagementScope object. HTHAnonymous
February 25, 2010
I encountered problems with LSASS CPU usage under Windows 2008, when running remote WMI queries from a dotnet application. Unfortunately, reusing a connected ManagementScope object did not help. The LSASS CPU usage rises at every call of ManagementObjectSearcher::Get(). Was this LSASS performance problem ever fixed for Windows 2008?