Launch XmlSerializer HUGE performance loss on 64-bit systems

I experience a really strong loss in HUGE performance when calling a simple XmlSerializer.Deserizlize () in a class with many fields.

NOTE I am writing code without Visual Studio at home, so it may have some errors.

My serializable class is flat and contains hundreds of fields:

[Serializable] class Foo { public Foo() { } [XmlElement(ElementName = "Field1")] public string Field1; // [...] 500 Fields defined in the same way [XmlElement(ElementName = "Field500")] public string Field500; } 

My application deserializes the input string (even a small one):

  StringReader sr = new StringReader(@"<Foo><Field1>foo</Field1></Foo>"); XmlSerializer serializer = new XmlSerializer(typeof(Foo)); object o = serializer.Deserialize(sr); 

Running the application on 32-bit systems (or with a 32-bit forced using corflags.exe), the code takes about ONE SECOND for the first time (generating the temp serialization class and that's it ...), then it is close to 0.

Launching the application on 64-bit systems, the code takes ONE MINUTE for the first time, then it is close to 0.

What can the system depend on for such a long time, during the first execution of the XmlSerializer, for a large class on a 64-bit system?

Right now I'm not sure if I should blame creating / deleting temp classes, initializing the xml, CAS, Windows Search, AntiVirus or Santa Claus name table ...

SPOILERS

Here are my tests, do not read this if you do not want me to be distracted by my (possible) analysis errors.

  • Running code from the Visual Studio debugger makes the code run FAST even on 64-bit systems.
  • Adding the (fully undocumented) system.diagnostic switch "XmlSerialization.Compile", which prevents the system from deleting temporary serialization classes, forces the code to run FAST even on 64-bit systems.
  • Taking the temporary class FooXmlSerializer created by the runtime, including .cs in my project and using it instead of the XmlSerializer, makes the code run FAST even on 64-bit systems.
  • Creating the same FooXmlSerializer class with sgen.exe, including .cs in my project and using it instead of XmlSerializer, makes the code run FAST even on 64-bit systems.
  • Creating the same FooXmlSerializer class with sgen.exe that references the Foo.XmlSerializers.dll assembly in my project and using it instead of XmlSerializer makes the code run SLOW even on 64-bit systems ( this scares me a lot )
  • Performance loss occurs only if the input for deserialization actually contains a large class field ( this also bothers me a lot )

For further explanation of the last point, if I have a class:

 [Serializable] class Bar { public Bar() { } [XmlElement(ElementName = "Foo")] public Foo Foo; // my class with 500 fields } 

Deserialization is slow only when passing the child element to Foo. Even if I have already done deserialization:

  StringReader sr = new StringReader(@"<Bar></Bar>"); XmlSerializer serializer = new XmlSerializer(typeof(Bar)); object o = serializer.Deserialize(sr); // FAST StringReader sr = new StringReader(@"<Bar><Foo><Field1>foo</Field1></Foo></Bar>"); XmlSerializer serializer = new XmlSerializer(typeof(Bar)); object o = serializer.Deserialize(sr); // SLOW 

EDIT I forgot to say that I analyzed the execution using Process Monitor, and I don’t see any task taking a lot of time from my application or from csc.exe or something related to the Framework. The system just does other things (or I I'm missing something), for example, antivirus, explorer.exe, Windows Search indexing (already tried to disable them)

+22
64bit xmlserializer
Nov 09 '10 at 6:53 on
source share
4 answers

I don’t know if this is related at all, but I had a problem with XSLT and found those pretty interesting comments from Microsoft 64-bit JITter:

The root of the problem is related to two things: firstly, the x64 JIT compiler has several algorithms that scale quadratically. Unfortunately, one of them is a debugging information generator. Therefore, for very large methods, it really gets out of hand.

[...]

some algorithms in 64-bit JIT that have polynomial scaling. We are actually working on porting the 32-bit JIT compiler to x64, but this will not see the light of day until the next side-by-side release of the runtime (as in "2.0 and 4.0" side by side, but 3.0 / 3.5 / 3.5SP1 were in-place releases). I switched this to a “suggestion” so that I could bind it to a JIT bandwidth work item to make sure this is fixed when the new ported JIT is ready to send.

Again, this is a completely different issue, but it seems to me that the comments on 64-bit JITters are universal.

+9
Nov 10 '10 at 2:00
source share

UPDATE

I was able to reproduce this, research shows that most of the time was spent on the JIT compiler:

JittingStarted: "Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderFoo", "Read2_Foo", "Instance Class SerializersTester.Foo"

You can easily prove that without any profiling tool.

  • Generate * .XmlSerializers.dll via sgen for x86 and x64 targets
  • Creating your own images via ngen.

You may notice that x64 generation will be much slower compared to x86 build

The exact reason lies in the x64 JIT internals (BTW is completely different from x86), and, unfortunately, I do not have enough free time to find it.

To avoid such a performance loss, you can generate a serialization assembly through sgen, reference it and compile the original image through ngen during the installation of the application on the end-user PC.

+6
Nov 09 '10 at 19:48
source share

To clarify the “XmlSerialization.compile”, this is what happens:

If we run the code without a .config file on 64-bit, it slows down.

If we add the following section to the .config file for the application

 <configuration> <system.diagnostics> <switches> <add name="XmlSerialization.Compilation" value="4"/> </switches> </system.diagnostics> </configuration> 

The result is the following:

  • File
  • .cs, DLL and PDB for serializer remain in temp folder
  • The serializer starts quickly, it is still slower than 32 bits, but finally acceptable (1-2 seconds instead of 60).

It is possible to create a DLL in debug mode (because there are PDB files available) to change the behavior of the JIT compiler, making it fast again ...

+3
Nov 10 '10 at 8:32
source share

Microsoft has known this since the release of 64-bit .NET:

http://connect.microsoft.com/VisualStudio/feedback/details/508748/memory-consumption-alot-higher-on-x64-for-xslcompiledtransform-transform-then-on-x86

From MSFT: "The x64 JIT compiler has several algorithms that scale quadratically .... this was what we have seen many times since the 64-bit environment was first released in 2005." and

“This problem is a) known and b) not entirely trivial to solve. This is a design problem with 64-bit JIT. We are in the early stages of replacing our 64-bit JIT implementation, so this will eventually get the address, but not in the timeframe CLR 4.0, unfortunately. "

0
Feb 21 '13 at 6:39
source share



All Articles