Executing MSBuild Targets in Parallel – Part 2


[ In this series – Part 1, Part 2 ]

Part 1 provided an introduction to using the new parallel task in the MSBuild Extension Pack. Here is the file I ended Part 1 with, having knocked a great deal of execution time off the build.

<Project ToolsVersion="4.0" DefaultTargets="Default" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$<MSBuildExtensionsPath>\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks"/>
  <ItemGroup>
    <MyTargetSets Include="1">
      <Targets>Target2</Targets>
    </MyTargetSets>
    <MyTargetSets Include="2">
      <Targets>Target1;Target3</Targets>
    </MyTargetSets>
  </ItemGroup>
  <Target Name="Default">
    <MSBuild.ExtensionPack.Framework.Parallel TaskAction="BuildTargetSetsInParallel" Targets="@<MyTargetSets>"/>
  </Target>
  <Target Name="Target1">
    <MSBuild.ExtensionPack.Framework.Thread TaskAction="Sleep" Timeout="1000"/>
  </Target>
  <Target Name="Target2">
    <MSBuild.ExtensionPack.Framework.Thread TaskAction="Sleep" Timeout="4000"/>
  </Target>
  <Target Name="Target3">
    <MSBuild.ExtensionPack.Framework.Thread TaskAction="Sleep" Timeout="2000"/>
  </Target>
</Project>

In this part I’ll cover maintaining state, limitations and some general tips.

State

Let’s start with state. By state I mean the Properties and ItemGroups that have been set during execution, the static ones should be fine assuming we don’t alter any conditional logic evaluations.

Limitation 1 – there is no support for passing ItemGroups within and between parallel executions

Limitation 2 – there is no support for passing Properties within and between parallel executions. You may of course use environment variables, files, registry etc. but no vanilla support.

What is supported is the passing of calling properties to the parallel target sets. Take this sample, executed using msbuild parallel2.proj /p:MyProperty=Mike

<Project ToolsVersion="4.0" DefaultTargets="Default" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Import Project="$(MSBuildExtensionsPath)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks"/>
    <ItemDefinitionGroup>
        <MyTargetSets1>
            <Properties>MyProperty=$(MyProperty)</Properties>
        </MyTargetSets1>
        <MyTargetSets2>
            <Properties>MyProperty=$(MyProperty)</Properties>
        </MyTargetSets2>
    </ItemDefinitionGroup>
    <ItemGroup>
        <MyTargetSets1 Include="1">
            <Targets>Target2</Targets>
        </MyTargetSets1>
        <MyTargetSets1 Include="2">
            <Targets>Target1;Target3</Targets>
        </MyTargetSets1>
        <MyTargetSets2 Include="1">
            <Targets>Target4</Targets>
        </MyTargetSets2>
        <MyTargetSets2 Include="2">
            <Targets>Target5</Targets>
        </MyTargetSets2>
    </ItemGroup>
    <Target Name="Default" DependsOnTargets="BuildSet1;BuildSet2"/>
    <Target Name="BuildSet1">
        <MSBuild.ExtensionPack.Framework.Parallel TaskAction="BuildTargetSetsInParallel" Targets="@(MyTargetSets1)"/>
    </Target>
    <Target Name="BuildSet2">
        <MSBuild.ExtensionPack.Framework.Parallel TaskAction="BuildTargetSetsInParallel" Targets="@(MyTargetSets2)"/>
    </Target>
    <Target Name="Target1">
        <MSBuild.ExtensionPack.Framework.Thread TaskAction="Sleep" Timeout="1000"/>
    </Target>
    <Target Name="Target2">
        <MSBuild.ExtensionPack.Framework.Thread TaskAction="Sleep" Timeout="4000"/>
        <Message Text="Target2 Value - $(MyProperty)" Importance="high"/>
    </Target>
    <Target Name="Target3">
        <MSBuild.ExtensionPack.Framework.Thread TaskAction="Sleep" Timeout="2000"/>
    </Target>
    <Target Name="Target4">
        <MSBuild.ExtensionPack.Framework.Thread TaskAction="Sleep" Timeout="4000"/>
        <Message Text="Target4 Value - $(MyProperty)" Importance="high"/>
    </Target>
    <Target Name="Target5">
        <MSBuild.ExtensionPack.Framework.Thread TaskAction="Sleep" Timeout="4000"/>
    </Target>
</Project>

We get

image

The key part here is the ItemGroupDefinition data set during the initial call. This saves any configured properties for use during execution.

Thumbs up Tip: If you have an InitialTarget set, this will be executed for every Target execution. You should either remove the InitialTarget configuration and call it manually, or condition it’s execution and then use the AdditionalProperties property so skip it’s execution on all but a pre-determined target.

Limitation 3 – there is no support for cancellation within a parallel execution. If a target fails though, any subsequent parallel target sets are not executed.

The cancellation limitation is something I plan to address shortly for the next release of the MSBuild Extension Pack.

Thumbs up Tip: If you only need a single target within a set to complete, set WaitAll=”false”. Note though that the other targets will still execute, but execution of the rest of your project will continue.

Thanks for taking time to read this and let me know how you get along with the task..

Mike

About these ads

5 thoughts on “Executing MSBuild Targets in Parallel – Part 2

  1. This is great, thank you.

    I’ve got a question, though. Our msbuild script is running unit tests and FxCop code analysis. I configured the targets to output an error message in case a unit test fails or fx cop analysis detects errors. A message contains specific information like “Unit Test FooViewModelTest.Close_ShouldCloseWindow() failed with .. exception”.

    Now when i run this using the Parallel task all i get is “Error Code: 1″. How can i get my error messages printed to the console?

  2. Thanks this has been really helpful to get me started.

    Is there an easy way to set a log prefix for each parrallel task in MSBuild? Once you move beyond trivial examples the output can get pretty messy trying to decifer the logs.

  3. Pingback: Dew Drop – April 19, 2012 (#1,309) | Alvin Ashcraft's Morning Dew

  4. Pingback: Executing MSBuild Targets in Parallel – Part 1 « Mike Fourie

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s