- Home
- LLBLGen Pro
- Architecture
Help needed for a performance challenge
Joined: 20-Jun-2006
Hi everyone,
I'm facing a performance-challenge. I have a project which was build using LLBLGen Pro 1.0.2005, Visual Studio 2005 (.NET 2.0) and it uses the C# adapter templates with webservices (downloaded from the 3rd party download section), which is slightly modified, but nothing relevant. We use an SQL Server 2005 database and LLBLGen runtimes version 1.0.20051.60621. That all works fine. But we are implemting this for a client and now our solution seems to choke on the amount of data. We did some performance-testing and it seems that almost all performance is lost to the serialization and deserialization. The ReadXML and WriteXML of the entities take up more than 90% of all the time spent on the transactions. We've also had implementations of the same software where this didn't happen. But it seems to be that we're passed some performance-thresholds of the software.
So we're considering all possible angles here to improve the performance, because what we have now is unacceptable. We are trying to reduce the data before it enters the Business Layer. This is something which has obviously nothing to do with LLBLGen. But we also need to try to make improvements in the Business Layer. I did some initial research and we started testing some of the possibilities. But as we also have time-pressure, I would like to show what I've got so far and maybe someone can help me with the architectural decissions or the implementation of it. Any help is appreciated. If possible we would like to stay on LLBLGen Pro 1.0.2005 and VS 2005, because an upgrade of those would not only mean more investments, but also an extra learning curve and implementation time, which we don't have to be honoust.
So far, I found 3 possible angles for improving serialization and deserialization in the Business Layer: 1. Moving to WCF with DataContractSerializer 2. Moving to Remoting with BinaryFormatter 3. Start using the FastSerializer for LLBLGen
I will elaborate a little bit on all 3 possibilities:
-
WCF WCF is a preferred way to go, because it is the direction Microsoft is going with SOA. Furthermore, test have proved that WCF with DataContractSerializer performs very well (see http://serialseb.blogspot.com/2008/01/comparing-serializations-or-why-flash.html and http://blogs.microsoft.co.il/blogs/sasha/archive/2008/01/20/wonders-with-wcf-s-datacontractserializer.aspx). All Entities are now generated with the [Serializable]-attribute, which should not be a problem for the DataContractSerializer. The DataContractSerializer will first serialize to an XML-Infoset object-structure in memory and the a BinaryEncoder would be used before it is sent over the wire.
-
Remoting The above two links show different performance for the Remoting architecture. But still, it would probably improve things drasticly. Remoting also uses the ISerializable interface, which should be okay with our Entities. The BinaryFormatter will use reflection to serialize the inner object structure.
-
FastSerializer I have not investigated this possibility at the moment.
For WCF and FastSerializer I'm not even sure it will work with LLBLGen 1.0.2005. I have no experience with LLBLGen 2.x and I don't know if I can use existing templates to build a working solution.
So far we have tried to implement the first possibility; WCF. But we have no luck so far. We created a WCF-service, added ServiceKnowTypes for all entities and OperationContracts for all methods that used to be WebMethods. These methods generally return EntityCollections. The WCF-Service compiles, but I'm stuck on creating the webreference. Since I'm on VS 2005 I do this manually by invoking svcUtil.exe:
"C:\Program Files\Microsoft SDKs\Windows\v6.1\Bin\svcUtil.exe" net.tcp://localhost:8083/WCFService/mex /language:cs /serializer:XmlSerializer /reference:"C:\Sources\bin\DataLayer.dll" /out:"C:\Sources\WCFClient\WCFServiceProxy.cs"
When using the XmlSerializer, I get warnings in my generated code:
// CODEGEN: Parameter 'GetOrdersResult' requires additional schema information that cannot be captured using the parameter mode. The specific attribute is 'System.Xml.Serialization.XmlElementAttribute'.
And the generated proxy method does not look okay either:
GetOrdersResponse GetOrders(GetOrdersRequest request);
It is generating proxy-classes for my Entities, although it should reference my original entities (as I did in the svcUtil commandline). I also reference to the project. Still, it misses the "additional schema information".
When I try the same with the DataContractSerializer (which is actually the preferred way), I get warning during the generation of the proxies:
Warning: The optional WSDL extension element 'body' from namespace 'http://schemas.xmlsoap.org/wsdl/soap12/' was not handled. XPath: //wsdl:definitions[@targetNamespace='http://tempuri.org/']/wsdl:binding[@name='NetTcpBinding_WCFService']/wsdl:operation[@name='GetOrdersPerStatus']/wsdl:output
And then the code looks like this:
void GetOrders();
Parameters and return-types seem to be lost in both cases. The warnings I get from the XmlSerializer are similar to what is discussed here: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=8927&StartAtMessage=25 .
I did try to build using the runtime, which was provided in that topic. But that obviously would not compile, because it was actually a 2.x runtime and our code was generated with LLBLGen Pro 1.0.2005. I also tried to change the result-types of our methods to IEntityCollection2, but that didn't help either.
I could use some help in getting WCF working for our project. Or maybe some insights or directions on how to implement Remoting or FastSerializer (which I believe is also based on Remoting). Or maybe a new approach, which is usefull for us. Again, any help is appreciated.
Thanks a lot, Rene Lergner
Joined: 20-Jun-2006
Hi again,
I'm really at al loss here. As I said, we're trying all possible approaches here. I thought maybe we should consider moving to LLBLGen 2.6 as it might contain usefull optimizations (for WCF or FastSerializing). So I downloaded LLBLGen 2.6 trial today (so I use latest runtimes and designer), installed it and opened our project. It took me a while before I could compile, because the generated code was not downward-compatible. I added some tasks and moved up the downward-compatibility-template and it compiled. Great! Not...
I tried svcUtil, but it gave me all kinds of exceptions. I tried to get help on those exceptions, but I could not find anything usefull. Then I thought I should start easy. I created a project, that references my genereted code and I try to fetch an entity. To my surprise I could not even create a DataAccessAdapter! This code fails:
DataAccessAdapter adapter = new DataAccessAdapter();
with this exception:
System.TypeInitializationException was unhandled Message="The type initializer for 'PrecalDataLayer.DatabaseSpecific.PersistenceInfoProviderSingleton' threw an exception." Source="PrecalDataLayerDBSpecific" TypeName="PrecalDataLayer.DatabaseSpecific.PersistenceInfoProviderSingleton" StackTrace: at PrecalDataLayer.DatabaseSpecific.PersistenceInfoProviderSingleton.GetInstance() at PrecalDataLayer.DatabaseSpecific.DataAccessAdapter..ctor() in C:\Sources\Precal 5 WCF Upgrade\PrecalWebService\DatabaseSpecific\DataAccessAdapter.cs:line 65 at PrecalWCFService.Program.Main(String[] args) in C:\Sources\Precal 5 WCF Upgrade\PrecalWCFService\Program.cs:line 32 at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart()
The constructor of the DataAccessAdapter calls PersistenceInfoProviderSingleton.GetInstance() and fails. This is the InnerException:
"An entry with the same key already exists." at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.SortedList`2.Add(TKey key, TValue value) at SD.LLBLGen.Pro.ORMSupportClasses.PersistenceInfoProviderBase.AddElementFieldMapping(String elementName, String elementFieldName, String sourceColumnName, Boolean isSourceColumnNullable, Int32 sourceColumnDbType, Int32 sourceColumnMaxLength, Byte sourceColumnScale, Byte sourceColumnPrecision, Boolean isIdentity, String identityValueSequenceName, TypeConverter typeConverterToUse, Type actualDotNetType, Int32 fieldIndex) at PrecalDataLayer.DatabaseSpecific.PersistenceInfoProviderCore.InitPdb101ArtikelenEntityMappings() in C:\Sources\Precal 5 WCF Upgrade\PrecalWebService\DatabaseSpecific\PersistenceInfoProvider.cs:line 161 at PrecalDataLayer.DatabaseSpecific.PersistenceInfoProviderCore.Init() in C:\Sources\Precal 5 WCF Upgrade\PrecalWebService\DatabaseSpecific\PersistenceInfoProvider.cs:line 59 at PrecalDataLayer.DatabaseSpecific.PersistenceInfoProviderCore..ctor() in C:\Sources\Precal 5 WCF Upgrade\PrecalWebService\DatabaseSpecific\PersistenceInfoProvider.cs:line 52 at PrecalDataLayer.DatabaseSpecific.PersistenceInfoProviderSingleton..cctor() in C:\Sources\Precal 5 WCF Upgrade\PrecalWebService\DatabaseSpecific\PersistenceInfoProvider.cs:line 25
I cleared all bin-folders to make sure I have no old binaries running and I checked all references to the runtimes. They all seem to be referencing the 2.6 runtimes.
I have the demo-version, so I have no source-code of the runtimes. I could really use some help here. When something so basic is not working, something is really wrong.
I would also like to know if I'm going the right direction for my performance-challenge or maybe someone would advise a better approach.
I will attach my project to this message. I would really like to know if someone can create a DataAccessAdapter from the generated code.
Thanks, Rene Lergner
Joined: 17-Aug-2003
We will get back to you shortly. You posted in the Architecture forum which isn't monitored at the highest priority. I saw your post this morning and bumped it up to the highest priority queue.
Joined: 21-Aug-2005
Hints:
1- In general I recommend the upgrade, since serialization is much optimized than on 1.0.2005.1
2- For LLBLGen 1.0.2005 I recommend using Remoting.
3- To use WCF, you should strictly follow the example in the docs and the example in our downloads section of the website. (i.e. don't use proxies, only use ChannelFactory and an Interface to hook the client with the service). .........................................................................................
Checking the attached lgp project.... I generated the code using LLBLGen Pro v.2.6, against .NET 2.0 and built a solution in V.S. 2005, referencing runtime libraries of v.2.6.
The exception is reproduced on instantiating a DataAccessAdapter in a Windows Form application.
We'll trace it down.
Joined: 20-Jun-2006
Hi Frans and Walaa,
Thanks for this usefull info. I will use these approaches and determine the pros and cons for the implementation and performance. I'd appreciate your help to get the 2.6 scenario working.
Thanks again! Rene Lergner
Joined: 17-Aug-2003
The project seems to be corrupt. In Pdb101Artikelen, you have two fields with the same fieldindex (index 20, AArtikelNummer and another field, sort on Index in the entity editor's field list). This might already have been the case in 1.0.2005.1, so it's unclear when this happened.
It's literally all over the place where it's wrong. As you have many entities, this isn't really doable by hand. I'll add a routine to the loader which corrects the indexes. (which are recalculated when a field is unmapped/remapped anyway).
Joined: 17-Aug-2003
I've mailed you a patched application core dll. Could you place that one in the demo installation folder overwriting the old one, load the project and re-generate code? This should correct any field indexes if there are duplicates.
If you don't receive the email, it's likely caught by spamfilters.
Joined: 20-Jun-2006
Okay, that's weird. My 1.0.2005.1 projects works fine. I attached it to this message. I think it is corrupted when it was saved as 2.6 project. I opened it in the 2.6 designer and I've changed some minor things in the tasks and the templates. I wonder what went wrong.
Rene Lergner
Joined: 17-Aug-2003
Rene wrote:
Okay, that's weird. My 1.0.2005.1 projects works fine. I attached it to this message. I think it is corrupted when it was saved as 2.6 project. I opened it in the 2.6 designer and I've changed some minor things in the tasks and the templates. I wonder what went wrong.
Rene Lergner
In 1.0.2005.1, the persistence data was stored in a different way, and duplicate indexes weren't a problem then.
(edit) the 1.0.2005.1 is corrUPT as well. Load Pdb101artikelen in the entity editor and sort on Index. You'll see AAlgemeenPercentageMeerprijs and AArtikelNummer both have index 20.
Joined: 20-Jun-2006
Otis wrote:
I've mailed you a patched application core dll. Could you place that one in the demo installation folder overwriting the old one, load the project and re-generate code? This should correct any field indexes if there are duplicates.
If you don't receive the email, it's likely caught by spamfilters.
Got it. That's really fast, man! I will try it immediately. I'll report back in a few minutes.
Thanks! Rene
Joined: 17-Aug-2003
Rene wrote:
Otis wrote:
I've mailed you a patched application core dll. Could you place that one in the demo installation folder overwriting the old one, load the project and re-generate code? This should correct any field indexes if there are duplicates.
If you don't receive the email, it's likely caught by spamfilters.
Got it. That's really fast, man! I will try it immediately. I'll report back in a few minutes.
Thanks! Rene
Yes we're quick .
Joined: 20-Jun-2006
Okay, very good! This is working now. So the issue in my second message is solved now!
Still working on multiple projects right now. I can continue with the LLBLGen 2.6 / WCF scenario and do some performance-testing. I will also try this with Remoting / FastSerializer and see if there is a difference.
Got two more questions:
Is it even possible to use WCF on the 1.0.2005 generated entities? We're now working on that and we followed the examples (with the ChannelFactory). Everything seems to run without exceptions, and on the server an EntityCollection is fetched and it contains an Entity. But when it is sent across the wire I got an empty EntityCollection. I tried to use the IEntityCollection2 in the contracts, but that doesn't make a difference. This approach is working in an asmx-webservices-scenario, but in WCF the contents of the EntityCollection is not serialized/deserialized. Any ideas?
Are there any templates for 1.0.2005 to use the FastSerializer?
We're making good progress now. Thanks alot! Rene Lergner
Joined: 21-Aug-2005
Definitely you should upgrade, v1.0.2005.1 has too many disadvantages for you: memory consumption, slower fetch speed, not suitable for modern stuff like .NET 2.0 (generics) WCF, it has bloated XML, and the fast serialization stuff isn't available.