May 2004 - Posts

Whidbey will brings us a shorter viewstate, guaranteed!

Note: this entry has moved.

In the following post I’m going to focus on the new viewstate serializer exclusively; keep in mind that there are other strategies being introduced in order to reduce viewstate size, like separation between viewstate as we know it today and a new control state.

Also, when using the term “serializer” I’m referring to the viewstate serializer unless otherwise noted.

 

New added support for common types

 

As I mentioned in a previous post, the serializer in ASP.NET v1.x was designed to handle only a few different types and it is not really a good idea to feed it with anything else.

 

In Whidbey, the serializer is being extended to support 10 additional types: IndexString, byte, char, DateTime, double, short, float, HybridDictionary, Enum and Color meaning that all these types now generate smaller footprints.

 

Aside from supporting new types, current serialization is being optimized. Let’s see some of the introduced changes.

 

Clever Gets Clever: type code = type + state

                                 

How is a Boolean handled? In v1.x they decided this was a very common type and added support for it into the viewstate serializer. This support means having a dedicated type code that represents a Boolean type thus avoiding the need to persist any additional extra information in order to properly identify it and de-serialize it later on.

 

This is how a serialized Boolean looks like in v1.x:

 

111 – code representing a Boolean type

60 – token representing the beginning of the stored state

116 or 102 – only one is used, depending on the instance value being true or false respectively.

62 – token representing the end of the stored state

 

Thanks to this type code optimization the footprint ends up being of 4 bytes which –believe it or not- is not that bad when compared for example to the footprint that would have been generated by the BinaryFormatter itself (~27 bytes).

 

First thing to notice in Whidbey is the reduction of token usage (char 60 and 62). In my opinion this “tokenized” approach of v1.x was largely useless so it’s a good thing to know it changed. Ok… so that’s two bytes shorter for a start.

 

Second thing we can see in Whidbey is that now the Boolean type code represents type plus state. Having two possible states bring us two different type codes: 104 for a Boolean with a value of false and 103 for a Boolean with a value of true. This means one less byte, which including the previous reduction, totals three less bytes, a 75% reduction, not bad. This is how a Boolean with a value of true looks like when serialized by Whidbey’s viewstate serializer:

 

103 – code representing a Boolean set to true

 

We miss you, Unit

 

There is a notoriously lack of support for the System.Web.UI.WebControls.Unit type in Whidbey.

 

In v1.x this type was assigned its own type code (49) which saved the serializer from having to store an –often large– string representing its assembly-qualified name.

 

In Whidbey, Unit is not backed up with a type code meaning that its full type name (yes, its full name and not its assembly-qualified one, wait till next title to learn why!) needs to be stored into viewstate, which means storing once the following additional string:

 

System.Web.UI.WebControls.Unit

 

None of the two serializers, the v1.x and the Whidbey one, do support any special serialization for this type; it’s being handled by a UnitConverter.

 

How this absence of a type code for Unit in Whidbey ends up reflecting in the final footprint?

 

Let’s take for example the following Unit instance:

 

Unit u = new Unit (“100px”);

 

In v1.x this instance will end up serialized into 8 bytes while in Whidbey final footprint will be of 39 bytes. Ugly… I know.

                        

Types from System.Web.dll assembly are loved (and around 82 bytes cheaper now!)

 

In v1.x, non-optimized types were handled down to a type converter when available. When this happens the assembly-qualified name of the type needs to be stored into viewstate which is not fun at all as it usually tends to be a quite large strings, i.e.:

 

System.Web.UI.WebControls.Unit, System.Web, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

 

In Whidbey, the serializer performs an additional check and if its dealing with a type that lives in the System.Web.dll assembly then it uses a special code (42) to signal it so only the full name of the type needs to be saved, i.e.:

 

System.Web.UI.WebControls.Unit

 

This avoids the need for having to store assembly-qualified names for any non-optimized types living in System.Web.dll assembly which will usually result in saving ~82 bytes of storage caused by the following string:

 

System.Web, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

 

 

There are other interesting things going on about the new serializer, like the special treatment some types as Color are given in order to produce the smaller possible footprint. I guess I will save them for a later post…

 

Posted by vga with 7 comment(s)
Filed under: ,

We need to get ScottGu to start blogging (again!)

Note: this entry has moved.

The other day while I was reconstructing my OPML file I stumped across ScottGu weblog and noticed he hasn’t blogged this year yet. I already know that based on my poor average of 2,6 posts/month I’m in no position for asking anyone to blog more regularly.

 

But… Scott you are “ScottGu”!! I mean… you *need* to post more regularly, or better said, *we need* you to post more regularly.

 

From personal experience I know that writing, reviewing, giving talks, having a family *AND* having a day job makes it really difficult to find the free time to blog. But… Scott… I want to know what you’re into, no matter if it’s about Whidbey, Orcas or NextCoolCodeNameGoesHere technology.

 

How many people will notice if VGA has a 2,6 posts/month? Actually just a few, one of them being my friend Daniel who likes to remember me -about every day- of that poor average… But Scott… I bet there are *lots* of people waiting to read stuff from you. So let’s make all these people happy!, right?

 

And… I’m making a public compromise of making 3 (yes, that’s three) posts per every post made by Scott -- offer valid through May04 only, sorry!  :-)

 

Posted by vga with no comments
Filed under:

Don't let the BinaryFormatter get at it!

Note: this entry has moved.

All the stuff written out there about viewstate will alert you that it was designed to handle only the following types: int, String, Boolean, Pair, Triple, Array, ArrayList, Hashtable and that trying to store anything else will incur in a performance loss. This is a well-known fact but what is not so well-known is the real why behind this.

 

One of the things I like to mention in my talks while addressing viewstate performance is something like “don’t let the BinaryFormatter get at your data”. I like all the “what??” this phrase causes at first :-) but after a bit of explanation everything comes back to normal again.

 

So, let’s see how the LosFormatter type –which happens to be the viewstate serializer- was designed for dealing with type serialization.

 

Its first approach is a very common one; it consists of checking if the type its dealing with it’s a simple one that it knows how to quickly serialize (the types listed at the very beginning of this post). In case it’s dealing with such a type it just needs to write out some form of header (usually a type code, which will be used to know what type follows) and then the customized (and fast) serialization happens. Note this is not really a novel ideal and it is exactly the same AltSerialization type already does.

 

Now, if the type LosFormatter is trying to serialize it’s not a supported one it will check if that type has an associated TypeConverter (yes, this implies some reflection code so you can start feeling the perf loss already, can you?). If a type converter is found then it will just say: “Hey you, type converter! Could you please serialize this type to a string representation for me please?”. It will then just use the output produced by the type converter.

 

But what happens if the type hasn’t an associated type converter. Well in this case the LosFormatter will say “Oh damn!, I don’t know how to serialize this type by myself and worse yet, it doesn’t have an associated type converter available to do the work for me; what am I gonna do now?” Its own answer is: “Let’s use the BinaryFormatter!”. Note that we’re talking here about instantiating a new BinaryFormatter and feeding it with the type in question. As you can imagine this is *lot* more work than any of the previous two steps, so you *really* want to avoid getting here in the first place.

 

 

Let’s put the above explanation into perspective; let’s say you’ve the following type:

 

[Serializable]

public class Customer {

     private String _lastname;

     private String _firstname;

     private String _address;

     private int _age;

     private int _code;

 

public Customer (String lastName, String firstName, String address, int age, int code) {

this._lastname = lastName;

           this._firstname = firstName;

           this._address = address;

           this._age = age;

           this._code = code;

 

     public String LastName {

           get {return _lastname;}

           set {_lastname = value;}

     }

     public String FirstName

     {

           get {return _firstname;}

           set {_firstname = value;}

     }

     public String Address

     {

           get {return _address;}

           set {_address = value;}

     }

     public int Age

     {

           get {return _age;}

           set {_age = value;}

     }

     public int Code

     {

           get {return _code;}

           set {_code = value;}

     }

}

 

Now let’s say you need to persist an instance of this Customer type to viewstate. If you just do so, the type won’t be one of the supported ones by LosFormatter and it won’t have a type converter associated so the BinaryFormatter will kick. Let’s try it:

 

 

Customer cust = new Customer("Garcia Aprea","Victor","1802 4th Clarius Ave.",29,31987);

LosFormatter los = new LosFormatter();

StringWriter sw = new StringWriter();

los.Serialize (sw, cust);

String resultSt = sw.GetStringBuilder ().ToString();

int size = sw.GetStringBuilder ().ToString().Length;

 

 

If you read size value you will notice that you just paid 436 bytes to serialize a Customer. For three short strings and two integers that seems just too much.

Let’s now code a type converter that knows how to persist a Customer to a String and get back a Customer from a String:

 

 

     public class CustomerConverter : System.ComponentModel.TypeConverter

     {

 

           public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)

           {

                if (sourceType == typeof(String))

                     return true;

                return base.CanConvertFrom (context, sourceType);

           }

 

           public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)

           {

                if (destinationType == typeof(String))

                     return true;

                return base.CanConvertTo (context, destinationType);

           }

 

           public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)

           {

                String state = value as String;

                if (state == null)

                     return base.ConvertFrom (context, culture, value);

                String []parts = state.Split ('#');

                return new Customer (parts[0], parts[1], parts[2], System.Convert.ToInt32 (parts[3]), System.Convert.ToInt32 (parts[4]));

           }

 

           public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)

           {

                if (destinationType == null)

                     throw new ArgumentException ("destinationType");

                Customer cust = value as Customer;

                if (cust != null)

                     return cust.LastName + "#" + cust.FirstName + "#" + cust.Address + "#" + cust.Age.ToString() + "#" + cust.Code.ToString();

                else

                     return base.ConvertTo (context, culture, value, destinationType);

           }

     }

 

And let’s attach it to the Customer type:

 

[TypeConverter (typeof(CustomerConverter))]

public class Customer

 

Run again the previous code used to feed a Customer instance to the LosFormatter and this time the footprint will be of 196 bytes! That’s quite a reduction, isn’t it?

 

Lastly, let’s play by LosFormatter rules and offer it a type that it knows how to handle:

 

Triplet t = new Triplet (cust.LastName, cust.FirstName, cust.Address);

Pair p = new Pair (cust.Age, cust.Code);

Pair custPair = new Pair (t,p);

 

Now feed the LosFormatter with custPair and not just an instance of Customer; this time the footprint will be of… 60 bytes! Another great improvement over the original 436 bytes.

 

I’m hoping that you can now see there are *real* benefits of knowing this stuff and that you could start taking advantage of it right away! :-)

Posted by vga with 14 comment(s)
Filed under:

Reflector 4.0 is out

Note: this entry has moved.

Unless you’re living under a rock you should have already heard about Reflector.

 

Good news is that the best utility for .NET ever created still continues to improve day after day. Lutz has just released Reflector version 4.0 which includes the following (these are just the new features I like most):

 

No reflection is being used – there is a new code model library. On the pros side, this basically means that the tedious file locking problems should go away. On the cons side, this means Reflector now likes to eat lots of more memory :-)

 

Whidbey support!! – A major hurra! for this one. All Whidbey new features are now supported (i.e. generics, etc). Plus… you can even load a Whidbey assembly with no Whidbey installed… what more do you want ugh?

 

Side by side versioning: this wasn’t possible in previous Reflection versions; now you can load for example v1.0 of System.Web.dll along with v1.1 of System.Web.dll; hint: stay away from loading multiple versions of mscorlib.dll, bad things will happen if you don’t.

 

For the last months I’ve been receiving drops of the beta from Lutz, giving some feedback, and discussing some of the pros and cons of the new “code model”… it was a really good experience!

 

Thanks Lutz for this excellent tool!!

 

Posted by vga with 5 comment(s)
Filed under:
More Posts