December 12th, 2005

How to improve command line performance

Buck Hodges
Director of Engineering

If you are using the tf.exe command line in scripts to convert from another version control system or to run other tasks that involve a lot of calls, there are several factors that have a large impact on the performance.  Other than the command files, all of the following applies to Visual Studio as well, but VS has the significant advantage of amortizing one-time overhead across a long execution time.  The command line pays one-time costs every time it runs, so it’s important to minimize those costs when performance matters.

Check LAN connection settings (applies now and for RTM)

First, check your LAN connection settings in Internet Explorer (Tools -> Internet Options -> Connections -> LAN Settings).  Often, the best settings are either to have no boxes checked or to have both of the bottom two checkboxes checked, “Use a proxy server” and “Bypass proxy server for local addresses.”  The reason is that the .NET 2.0 framework network code gets its settings from the settings in IE.  Prior to the December CTP, there was no way to override this.

How much difference does it make?  It makes a 1 – 2 second difference per tf.exe execution on our network.  Of course, these settings may not work on your network, either for tf.exe or IE, depending upon your network configuration; you’ll need to test it.

Beginning with the December CTP, there is an optional registry setting that you can use to tell the Team Foundation client to bypass the proxy server without changing your IE settings.  In HKCU (per user) or HKLM (global), you can create the registry entry SoftwareMicrosoftVisualStudio8.0TeamFoundationRequestSettingsBypassProxyOnLocal of type string with the value “true” to get the improved performance.

Avoid running tf.exe on the application tier (applies now and for RTM)

You might think that running tf.exe on the application tier would give you the best performance.  After all, the network communication would be minimized, right?  Well, it doesn’t work that way.

Team Foundation has a registration service that the client uses in order to get to the various services, including version control.  When a client app, such as tf.exe, VS, or your own custom application, needs to use version control, the TF client code must request the service definition from regsistration service on the server.  To avoid constantly requesting service registration information that rarely changes, the client-side registration code maintains a cache and only makes the server call when the cache is out of date.

However, when the client code executes on the application tier, the client-side registration code detects that it is running on the application tier and does not cache the service registration information.  Additionally, there’s a bug (that won’t even be fixed for RTM due to being posponed to v2) that results in the client-side registration code requesting the registration information twice.  So, every execution of tf.exe invokes two registration service information requests when run on the application tier.

The result is that tf.exe is faster when run on a machine other than the application tier (both now and for RTM).  So how much difference does this make?  It can save 1 – 3 seconds.  How much it saves really depends on some additional factors.  The call to get the registration information may take a few hundred milliseconds or so (multiplied by two for the app tier).  The rest of the savings comes from SOAP proxy class not being generated.  The client-side SOAP proxies other than version control use the standard SOAP proxy support provided by the .NET 2.0 framework where the client-side proxy class is generated by wsdl.exe at build time.  At runtime, the framework uses reflection to dynamically generate, compile, and load serialization assembly the first time the proxy class is used.  As you might guess, that’s very expensive for the command line.

The best setup would be a client machine that’s connected to an application tier via a fast, local network switch.

Use NGen with tf.exe (applies to beta 3 refresh and earlier)

With .NET 2.0, NGen has improved substantially.  NGen generates native image dlls for .NET assemblies and executables (you can find more details on NGen here).  The result is that less time is required to load and run the assemblies.

The December CTP and beyond will use NGen during setup to create the native images.  For beta 3 and beta 3 refresh, you can use ngen.exe to reduce the time to load and run tf.exe.  You only need to run ngen.exe once.  Bring up a Visual Studio 2005 Command Prompt (Start -> All Programs -> Microsoft Visual Studio 2005 -> Tools -> Visual Studio 2005 Command Prompt), change to the %PROGRAM_FILES%Microsoft Visual Studio 2005Common 7IDE directory and execute the following command.

ngen install tf.exe

NGen will examine tf.exe’s dependencies and generate native images for them.  The result will be a faster start up time for every execution of tf.exe.  How much time does it save?  This may save up to 200 ms.

Generate command files for sequences of tf.exe commands (applies now and for RTM)

Team Foundation Server uses Windows authentication (NTLM) to authenticate users.  That means that every initial request from tf.exe must go through the NTLM handshake.  Since many tf.exe commands make only one or two requests, that means that most requests incur the authentication overhead.  For a long sequence of tf.exe commands, that overhead can really add up.

If you are going to run a sequence of tf.exe commands, you can put them into a command file.  Preliminary documentation for command files is available here on MSDN.  The documentation refers to some addtional commands that are not available now, such as cd, rem, quit, and exit.  You can also run “tf @” and start typing or piping input as it reads from the standard input stream (experiment with it).

When you execute a command file, only the first request incurs the authentication overhead.  After that, the authenticated connection is reused[1].  How much time does this save?  Well, there’s no quick answer here.  It’s the product of the authentication overhead multiplied by the number of authentication requests you can avoid by using command files.  Additionally, it’s the runtime startup overhead multiplied by the number of times you would have invoked tf.exe (this isn’t nearly as significant if you’ve used ngen.exe as explained previously).

Summary

We’ve covered the most important command line performance issues that you can control: LAN settings (or TFS registry setting for RC/RTM), not running tf.exe on the application tier, running ngen on the beta 3 tf.exe, and using command files to avoid authentication overhead.  If you follow the recommendations discussed above, the tf.exe performance should be noticeably better.

___________

[1]  Technically, it’s the first request on each thread.  Uploads, downloads, and pending adds (if you are adding more than 200 files at a time) use multiple background threads.  If all of the authenticated connections are in use, a thread will open a new connection that must be authenticated.  The authenticated connections are part of a pool (connection group) that are reused as needed.

Author

Buck Hodges
Director of Engineering

Director of Engineering, Azure DevOps

0 comments