May 2011 Entries

I have recently been exploring the wonders of PowerShell. I also recently worked through some deployment / configuration issues and thought I would bring my newly acquired appreciation of PowerShell to the mix.

I had never given PowerShell a second thought. I really had no idea what it was or how it was used. This is very surprising given my perl background. Once I gave it a chance, I loved it.

One of the most exciting things about PowerShell is that unlike with regular scripting languages, you are not dealing with text. You are dealing with objects. More specifically, you are dealing with DotNet objects. So when you run a cmdlet like get-service, you don't get text back, you back a ServiceController. This means that you can easily start and stop services:

$service = get-service $serviceName

if ($service –ne $null)

{

$service.Stop()

}

 

This is very nice and so much easier being able to deal with objects.

With this in mind, how do we deal with the config files?

Instead of simply dealing with text, we can deal with an xml document. Powershell will actually "strongly type" the document, sort of. Consider a script like this:

$xml = [xml](get-content($path))

$xml.Save($path+ ".old")

$runtime = $xml.configuration["runtime"]

if($runtime.gcServer -eq $null)

{

$gc = $xml.CreateElement("gcServer")

$gc.SetAttribute("enabled", "false")

$runtime.AppendChild($gc)

}

$runtime.gcServer.enabled = "false";

$xml.Save($path)

 

This lovely little bit of magic will add the following configuration setting if it does not already exist

 

<configuration>

<runtime>

<gcServer enabled = "false"/>

</runtime>

</configuration

 

There is a subtle point to note here. If there are no child elements to runtime to start with, $xml.configuration.runtime will be a string. If runtime already has elements, it will be an xml element. $xml.configuration["runtime"] will always be an xmlelements. This subtle distinction caused me some confusion initially and complicated writing my little script.

 

This type of script makes it easy to make a change to a deployment target, especially if you must make the same change to several servers.

It also makes it easy audit and verify that the server is in fact configured properly.

 

Turns out there are lots of uses for this new (at least new to me) tool for the ever growing tool box.

 

What are you doing with power shell?

I have been researching some memory issues and come across something that surprised me the other day. The generic List hides what can potentially be a substantial memory hog.

This is not a memory leak. It is just a fairly benign looking object with some simple looking code that may cause your application to use substantially more memory than you may initially think likely.

It is common to write code similar to this:

           
public static IList<string> GetNames(Type enumType)
{
    if (!enumType.IsEnum)
    {
        throw new ArgumentException("Type '" + enumType.Name + "' is not an enum.");
    }
    List<string> list = new List<string>();
    foreach (FieldInfo info in from field in enumType.GetFields()
        where field.IsLiteral
        select field)
    {
        list.Add(info.Name);
    }
    return list;
}

 

The details are not as important as the pattern, we are looping through a collection and adding items to the List.

Consider the implementation of the Add method. From Reflector we get:

public void Add(T item)

{

if (this._size == this._items.Length)

{

this.EnsureCapacity(this._size + 1);

}

this._items[this._size++] = item;

this._version++;

}

 

 

This looks innocent enough. The problem is in the EnsureCapacity method. This may be a little sublte:

 

 

private 									void 									EnsureCapacity(int min) 

 

{ 

 

 									if (this._items.Length < min) 

 

    { 

 

 									int 									num = (this._items.Length == 0) ? 4 : (this._items.Length * 2); 

 

 									if (num < min) 

 

        { 

 

            num = min; 

 

        } 

 

 									this.Capacity = num; 

 

    } 

}

 

If you follow a common pattern of instantiating your list with the default constructor, we will start with an empty list. The first time we call Add, we will hit the EnsureCapacity. The length will be 0 and num will get a value of 4. After adding a few more items, we will again hit EnsureCapacity and this time we will double the size of the list. Every time after this initial call to EnsureCapacity we will double the size of the list.

If the number of items in the list is close to a power of two but not over it, we will have good memory utilization, but we can get into trouble if we are over by just a little bit. If the size of the list is 255, we will have ideal memory usage, but if there are 257 items in the list, we will have allocated enough room for 512 items even though we only need half that.

Why would we do such a thing? Look at the implementation of the Capacity property:

public int Capacity

{

get

{

return this._items.Length;

}

set

{

if (value != this._items.Length)

{

if (value < this._size)

{

ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value,

ExceptionResource.ArgumentOutOfRange_SmallCapacity);

}

if (value > 0)

{

T[] destinationArray = new T[value];

if (this._size > 0)

{

Array.Copy(this._items, 0, destinationArray, 0, this._size);

}

this._items = destinationArray;

}

else

{

this._items = List<T>._emptyArray;

}

}

}

}

 

We run the risk of using substantially more memory than we need to avoid the call to Array.Copy. This method is actually implemented as unmanaged code, so I don't know what it is actually going on there. My guess would be "unsafe" pointer manipulation.

 

My advice, provide a reasonable initial capacity when declaring lists (this will avoid the initial calls to EnsureCapacity). Err on the side of too big because if the List decides it needs to grow, if will double in size compared to you initial estimate. If it could be 500, go ahead and make it 600. As long as the actual values are at least half of what you set, you will probably be better off than if the list grew on its own by powers of 2 while incurring the Copy overhead at each step.

 

What are your thoughts?

 

 

 

 

I will be speaking at the Carolina Code Camp this weekend http://codecamp.developersguild.org/.

There will be 45 sessions by 30 different speakers spread over 9 tracks. It should be a good time.

The biggest problem for anyone attending is deciding which sessions to go to. With 9 tracks there will be many great sessions going on at the same time.

From a presenter perspective, that ups the ante. I am very much aware that when I am speaking there are 8 other folks that you could be hearing instead.

My presentation is titled "Getting Back in the Game". The target audience is Recent Graduates, Developers who have been out of the industry for a while, IT professionals looking to make the transition to a developer, as well as active developers who want a different type of job (web developer looking to get into Silverlight for example).

In this session, we will explore the problem of "How do you get opportunities without experience" and "How to get experience without opportunities".

Much of the thought behind this material comes from personal reflections while I sat in on recent interviews. It was very frustrating watching candidates flounder over the questions of having relevant experience and thinking about what they could do to shore up this weakness.

If you fit into this target audience, I hope you will come see the presentation and hopefully get some fresh insight.

If make hiring decisions, maybe you can join the discussion and add your perspective to the conversation.

Whether you come to my session or not, there will be a lot of great material discussed all day long.