HaveComputerWillCode.Com

Welcome!
Life is a Non-Deterministic Finite State Automata
Automation ? (*pGeekiness)++ : Code /eneration;

December 5, 2010

T4 Performance: From TextTemplatingHost to Preprocessed Templates

Filed under: Performance,Programming — Tags: , , , , — admin @ 7:44 am

I’ve been moving my code generators and infrastructure from Visual Studio 2008 to Visual Studio 2010 and making use of the new ‘Preprocessed T4 Templates’ feature. There’s no metrics out there I could find, so here’s mine.

Within 2008, I had my own host that loaded the TT files as they were required, used Microsoft’s Text Templating Engine to parse them on the fly and then generate my code. Performance was pretty good but it meant parsing the TT files every time. 7.5 seconds for 140+ files is admirable!

In 2010, I’ve moved over to Preprocessed Templates and the performance has improved three fold:

In all, there’s about 2 megabytes of generated C# code from the above generation job – in about 2.5 seconds. Preprocessed Templates are clearly the way to go!

My motivation for doing this isn’t speed though. As much as I would like to ship raw T4 templates with my application, it would appear it is not legal to distribute the Text Templating Engine along with your product. This means that unless you are targeting the Visual Studio development community, you cannot rely on the TextTemplating DLL’s being there. So you have to preprocess your templates and distribute a compiled version of that instead. The Engine comes with Visual Studio and various addons (in the Microsoft.VisualStudio.TextTemplating.* DLL’s) so developers don’t notice it’s missing until they distribute their application :-) It would be awesome if Microsoft could push out the T4 Engine as part of a regular update because it’s a mighty useful piece of kit.

The only way around this at the moment (apart from breaking the law or arranging something with the doods in Redmond) is to distribute the C# or VB.Net project containing the T4 files so your customers can regenerate them onsite if they need to modify the output. Or use the Open Source / reverse engineered version mentioned on the Stackoverflow link above. I don’t think either is ideal, but it seems to be the best that can be done at the moment. I would love to hear otherwise!

L8r!

December 3, 2010

Launching LEViewer.EXE from within SCVMM

Filed under: ALM,Testing — Tags: , , , — admin @ 8:31 am

(and using SCVMM PowerShell to query running Lab Center Environments)

You can download the PowerShell script here (CORRECTION: 4th December: I fixed a bug in Filter-LabMachines so it returns $machine instead of $InputObject).

The PowerShell interface that drives SCVMM is awesome but it doesn’t provide anything out of the box that helps you write queries against virtual machines deployed by Lab Center. As far as SCVMM is concerned, any VM’s deployed by Lab Center are just VM’s. This post will (eventually) provide a few crude helper methods so you can use PowerShell to show all running virtual machines grouped by Project, Lab Center environment or whatever.

When using Lab Center and you right click on a running environment and select “Connect”, it launches the Lab Environment Viewer (LEViewer.EXE):

Ultimately, the virtual machine(s) you connect to using LEViewer.EXE are running on a Hyper-V host managed by SCVMM in a mysterious part of your Enterprise. For reasons of pure geekiness, I wanted to launch that viewer from within the SCVMM PowerShell console based on Virtual Machine queries. How?

By using Process Explorer, it’s easy to inspect the running LEViewer.EXE command line and you’ll see something like this:

Kool! So if we can get at the TFS Collection, the Environment and the Virtual Machine we want to connect to from within SCVMM, we can launch LEViewer in that context from PowerShell. We can do that!

When you deploy a virtual machine using Lab Center, it is given an aesthetically pleasing random-GUID name like so:

But it’s “Description” field within SCVMM yields all of the useful information we require (the Description field is set by Lab Center). Right click the machine and select Properties:

So all we have to do is to extract that information and construct the command line. To make it easier, I’ll do things ‘the properish way’ and write helper functions that can be used in the PowerShell pipeline:

function global:Filter-LabMachines 
{
param([Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        	[PSObject[]]$InputObject)

    BEGIN 
	{
   	}	
    PROCESS 
    {
        	foreach ($machine in $InputObject) 
		{
			try
			{
				# Turn the Description into an Object so we can walk it. [xml] has to be one of the most underrated PowerShell features *EVER!*
				$labDescription = [xml] $machine.Description;
				$crudeThrowawayChecker = $labDescription.LabManagement.LabEnvironment;
		
				# Add some dynamic member properties
				Add-Member -MemberType NoteProperty -Name LabTfs -InputObject $machine -Value $labDescription.LabManagement.TFS;
				Add-Member -MemberType NoteProperty -Name LabProject -InputObject $machine -Value $labDescription.LabManagement.Project;
				Add-Member -MemberType NoteProperty -Name LabProjectCollection -InputObject $machine -Value $labDescription.LabManagement.Collection;

				Add-Member -MemberType NoteProperty -Name LabEnvironmentId -InputObject $machine -Value $labDescription.LabManagement.LabEnvironment.Id;
				Add-Member -MemberType NoteProperty -Name LabEnvironmentName -InputObject $machine -Value $labDescription.LabManagement.LabEnvironment.InnerText;

				Add-Member -MemberType NoteProperty -Name LabSystemId -InputObject $machine -Value $labDescription.LabManagement.LabSystem.Id;
				Add-Member -MemberType NoteProperty -Name LabSystemName -InputObject $machine -Value $labDescription.LabManagement.LabSystem.InnerText;

				# If we get to here, it is probably a candidate for being a Lab-Deployed Virtual Machine
			        $machine;
			}
			catch
			{
	
			}
		}
        }
    	END 
	{
    	}
}

The idea is that you use something like this to identify all Virtual Machines managed by Lab Center:

Get-VM | Filter-LabMachines

Get-VM is part of SCVMM; when the virtual machines are piped through our Filter-LabMachines, we only pass lab machines down the pipeline. I have decided that a VM is a Lab Machine if it has a ‘Description’ field that looks like XML. The additional crude test for this is to use the [xml] caster in PowerShell and then walk the object to extract the properties we need. Note the use of ‘Add-Member’: I augment the $machine with the value of the Lab properties so I don’t have to recalculate them. The PowerShell type system *ROCKS!*

So with a list of machines that were (probably) deployed by Lab Center, we can now dump the SCVMM Name and the name of the Virtual Machine as seen in Lab Center (see LEViewer.EXE above):

Get-VM | Filter-LabMachines | Select-Object -Property LabProject,LabEnvironmentName,LabSystemName

So it looks like this:

Now we can use PowerShell to show all running Lab Center environments and the projects to which they belong. ie:

Get-VM | Filter-LabMachines | Where-Object { $_.Status -eq "Running" } | Select-Object -Property LabEnvironmentName,LabSystemName | Sort-Object -Property LabEnvironmentName | Format-Table -GroupBy LabEnvironmentName

And finally to launch LEViewer to connect to our environment from PowerShell in SCVMM, we just need to pick an environment with a running virtual machine and pipe it into Start-LEViewer:

Get-VM | Filter-LabMachines | Where-Object { $_.LabProject -eq "Grom" } | Where-Object { $_.Status -eq "Running" } | Sort -Property LabEnvironmentName -Unique | Start-LEViewer

The helper method ‘Start-LEViewer’ is here:

function global:Start-LEViewer 
{
param([Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        	[object[]]$InputObject)

    BEGIN 
	{
    }	
    PROCESS 
	{
        foreach ($machine in $InputObject) 
		{
			# Turn the Description into an Object so we can walk it. [xml] has to be one of the most underrated PowerShell features *EVER!*
			$labDescription = [xml] $machine.Description;
		
			# The Command Line of a spawned LEViewer looks something like this:
			#
			# "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\leviewer.exe" /tfsUri:http://win-tskurfclu7g:8080/tfs/defaultcollection /environmentUri:vstfs:///LabManagement/LabEnvironment/192 /systemUri:vstfs:///LabManagement/LabSystem/193
				
			$executable = "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\leviewer.exe";
			$p = "/tfsUri:$($labDescription.LabManagement.TFS)/$($labDescription.LabManagement.Collection) /environmentUri:vstfs:///LabManagement/LabEnvironment/$($labDescription.LabManagement.LabEnvironment.Id) /systemUri:vstfs:///LabManagement/LabSystem/$($labDescription.LabManagement.LabSystem.Id)";
 
			[System.Diagnostics.Process]::Start($executable, $p);
		}
	}
	END
	{
	}
}

Thanks to this link for information on writing PowerShell Advanced Functions to use the Pipeline.

Tchau!

Powered by WordPress