Archive for July 27th, 2010

I have to write this down for me and others. It’s a headache each time I do it and I imagine for others as well. The problem at hand is how to make a build definition for a solution (or a new build definition for a solution already having a build definition) which is build on a build machine hosting multiple build agents (scenario not endorsed by Microsoft).

Here are the steps:

  1. If you don’t know what you are doing ask someone who does and go to step 10. If you don’t have someone to ask you can still proceed but at your own risk.
  2. Log on onto the build machine as an administrator (just to avoid pesky security checks)
  3. Go to c:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies – this may vary due to the OS being 32 or 64 and if you’re using TFS2008 (you go to vs 9.0 directory) or if you’re using TFS2010 (you go to vs 10.0 directory)
  4. Copy TFSBuildService.exe as TFSBuildService2.exe (just make sure you have different executables for each build agent, I use numbers added to the name of the file)
  5. Copy TFSBuildService.exe.config as TFSBuildService2.exe.config (same logic as above)
  6. Edit TFSBuildService2.exe.config:
    • such that the “port” and “InteractivePort” have values not yet used. For the second agent these would be 9193 and 9194 which I will be using later in the process.
    • Here you can also fool the build agent to use whatever version of MSBuild you want by modifying MSBuildPath. For example I use the MSBuild of .Net 4.0 on a TFS2008.
    • Modify “SourcesSubdirectory” to “Sources\projectname” where projectname is an arbitrary value, just make sure it’s different for all build agents
    • Modify “BinariesSubdirectory” to “Binaries\projectname” – same logic as above
    • Modify “TestResultsSubdirectory” to “TestResults\projectname” – same logic as above
  7. Create a service for the build agent. Open a visual studio command prompt (will save you to write fullpath to sc.exe) and run the command: sc create VSTFBUILD2 binpath= “C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\TFSBuildService2.exe” displayname= “Visual Studio Team Foundation Build – projectName” start= auto. Observations:
    • the name of the service VSTFBUILD2 should differ from all other build agent services and thus I added the 2 suffix
    • the TFSBuildService2.exe should be the one you created at step 4
    • the display name is not very important but helps in identifying the service in the service manager window
  8. Go to service manager window (start\control panel\administrative tools\services), find your newly created service, go to properties, the log-on tab and modify there to make the service to log on as the TFSService (default account for the TFS). Make sure you’re using also the domain there if you are in a domain.
  9. Start the service
  10. Create a folder where the build results will be added. Something like “c:\b\pname”. Be carefull to choose as shorter names as possible to not hit the 240 char limit of TFS when getting all the source code. Share this folder with the people that need to access build results and make sure TFSService has full rights on it
  11. Log on to the TFS machine
  12. Start visual studio (must have team explorer installed).
  13. Use team explorer to navigate to your sollution and right click on the Builds and select Manage Build Agents. If you don’t see the option you may not have rights – get them.
  14. Click New. Choose a display name. I choose buildmachine_2. In the computer name add buildmachine and the communication port you set at step; in this case 9193. Set the agent status to Enabled and finish.
  15. Log on to your development machine. Use team explorer and go to the builds folder of your sollution.
  16. Right click builds and choose New build definition.
    • Put a build definition name there,
    • select the trigger,
    • select the workspace (what needs to be retrieved by the source control) and put in the build agent folder the folder created at step 10.
    • In the Build defaults select in the build controller dropdown buildmachine_2 (if it is not yet visible there restart visual studio and try again). Also put into the build output folder textbox the UNC path to the share created as step 10.
    • In the project file put the source control path to the TFSBuild.proj if you have it already, if not you should be able to create it from this tab
    • done here. After saving this you should see your build definition in the builds folder in team explorer.
  17. In the TFSBuild.proj file (seen at last step of step 16) modify:
    • BuildMachine – buildmachine_2 – this is just to make sure because it should be ignored normally
    • BuildDirectoryPath – put the full name of the directory created at step 10 (not the UNC path! but the path as seen when logged-on on the build machine, like “c:\b\pname”)
  18. Done. You should be able to queue a new build.
  19. Have fun.

Comments No Comments »

The question: if you use a linq query over a list of elements and you want to select only the first element, using the First extension, does the processing continue after hitting a match? Why is this important? it’s because the query might be very heavy and you don’t really need to process all elements, only if an element matches your query.

Here is the test:

    class Program
    {
        static void Main(string[] args)
        {
            List<Element> lst = new List<Element>();
            lst.Add(new Element("1"));
            lst.Add(new Element("2"));
            lst.Add(new Element("3"));
            lst.Add(new Element("4"));
            lst.Add(new Element("5"));

            var res = (from e in lst
                       select e.Name).First();
            Console.ReadKey();
        }
    }

    class Element
    {
        private string m_name;
        public string Name
        {
            get { Console.WriteLine(m_name); return m_name; }
        }
        public Element(string name) { this.m_name = name; }
    }

And the answer: Linq will stop after the first element corresponding to your query is found.

Comments No Comments »

I’ve been playing alot with reflection lately to analyze code and apply metrics on it. Unfortunately on large projects this means dealing with hundreds of thousands of objects representing classes, methods and the like. When parsing them I hit a wall because the code would run for hours before spitting out the results. I started looking for optimizations and one of the choices was to replace for cycles with linq queries. That added some benefits but still not enough.
What I saw was that my quad core processor was utilizing a single core and of course I started thinking threads but I am lazy. Luckily I remembered about PLinq. I haven’t used it until now so I did a little bit of research. Well research is a harsh word, more like reading a bit on how to use it and I found that is actually easy to switch a query from Linq to PLinq. At the most basic level you just have to select not from your collection but from your collection marked for paralelization. You can do that by saying myCollection.AsParallel(). Well ain’t that easy?!
Just so as you can see the importance of this, my processing went down from 5 hours to 1 hour.
You can see below some code that you can use to check the performance. Just be sure to run it on a multi core machine :)

            Random r = new Random((int)DateTime.Now.Subtract(DateTime.Today).Ticks);
            List<int> list = new List<int>();
            for (int i = 0; i < 30000000; i++)
            {
                list.Add(r.Next());
            }

            DateTime t1 = DateTime.Now;

            var paraleled = (from i in list.AsParallel()
                             where CheckPrime(i)
                             select i).ToList();

            DateTime t2 = DateTime.Now;

            var unparaleled = (from i in list
                               where CheckPrime(i)
                               select i).ToList();

            DateTime t3 = DateTime.Now;

            Console.WriteLine("Paralel linq select : " + t2.Subtract(t1).TotalMilliseconds);
            Console.WriteLine("Normal linq select : " + t3.Subtract(t2).TotalMilliseconds);

One thing to highlight here is that the “slow” processing is emulated by a CheckPrime method which unfortunately is not as slow as I would want. If you want to see real benefits, modify to call a more intensive method there.

Comments No Comments »