1.5 to 2.1.4 Performance Hit

1.5 to 2.1.4 Performance Hit

Old forum URL: forums.lhotka.net/forums/t/3460.aspx


CodeWampus posted on Friday, August 31, 2007

I've written several apps using CSLA 1.5, including a medium sized commercial app with about 20 CSLA editable object classes and matching collection object classes and 10 name-value lists.  I upgraded to VS2005 and .Net 2.0 in the middle of that project but stayed with CSLA 1.5 since it was fulfilling all my needs.  

More recently, I've been gearing up on an ambitious project that could potentially use all of the DataPortal methods: Local, Web Services, Remoting, etc.  In order to give myself the widest range of options, I planned to migrate to CSLA 2.1.4.

As a test case, I selected an existing CSLA 1.5 switchable object with 12 properties and coded up 2.1.4 versions of the object and an EditableChildCollection to go with it, using the Templates and ProjectTracker as my models, with some minor tweaks covered in your 2.1 e-book. I then wrote a simple test program to read the collection and display it in a grid.  The data for the collection is an SQL Server table with 35K rows.

To my surprise, the 2.1.4 version took almost 26 times as long to load the collection.

1.5            1.6 sec.

2.1.4      41.6 sec.

I loaded the collection into an Infragistics grid, which gives you the ability to sort by clicking on a column header.  Sorting in this way also showed the same order of magnitude time difference between the old and new.  My new objects have "Slow" attached to them!

I'm assuming this is my problem and not CSLA's, but I'm at a loss as to where to start looking.  Despite the many differences between the old and new objects, the code path is virtually identical, at least for this operation.  The difference seems to be in the objects and the way they perform in a collection.  Any suggestions?

xal replied on Friday, August 31, 2007

Well, do your objects have rules? What kind of rules? Are you using instance or static rules? Static rules perform WAAAAY better during an intense loading such as this scenario.
Do you use reflection at any step? Or the rules provided by csla? These rules are pretty good for general use, but when you have a huge data load, it may not perform as well as a hand coded rule since they use reflection.

Are you running validations in both versions upon load?
Are you using remoting or running local? Do you have any circular references?
Are you using n-level undo at any point? Note that when binding to the grid, you'll be increasing the edit level for all of your objects, and that takes a lot of time. Beware of circular references here too mark them as NotUndoable().

Did you try profiling the app to see where the bottleneck is?


Andrés

CodeWampus replied on Friday, August 31, 2007

Thanks for the reply!  It led me to the problem.

I'm running local.  No circular references. No n-level undo.

My entire program, outside of the CSLA objects, is:

Dim testCollection As EventHeaders = EventHeaders.GetEventHeaders()

grdListView.DataSource = testCollection

Since this was a first-time-test object, there were no validation rules, no modifications to CSLA, and the only authorization rule on the object and the collection was the following:

Public Shared Function CanGetObject() As Boolean

Return ApplicationContext.User.IsInRole("EHUser")

End Function

This seemed fairly innocuous, but to control for all variables I changed it to:

Public Shared Function CanGetObject() As Boolean

Return True 

End Function

Load time dropped from 40+ seconds to 1.1 seconds!!!  I don't know why this authorization is so resource heavy, but at least now I know where to focus my attention.

xal replied on Friday, August 31, 2007

Well, I don't know how I led you to figuring that out! :)

Anyway, in scenarios like this, it is best to have the CanGetObject at the collection level instead of the child, so it will only ever run once per fetch (unless you have some very specific security).
While string comparison or creation seems trivial, it can hog your resources as you can see. Believe it or not, the whole reason for moving to static rules started out because of one string that gets created when a rule is added to an object.
In this case you were probably looping through a list of roles (that's what most people do at least) 36k times and comparing them one by one. If your roles are rather "fixed" (and they usually are), it is sometimes a good idea to have the answer to the IsInRole question cached somewhere...

Your class could call something like SecurityHelper.IsEHUser and that static property caches the result for the test, like:

Public Class SecurityHelper
Private Shared mIsEHUser As Boolean
Public Shared ReadOnly Property IsEHUser As Boolean
    Get
       Return mIsEHUser
    End Get
End Property

Public Shared Sub CheckSecurityAccess()
       mIsEHUser = Csla.ApplicationContext.User.IsInRole("EHUser")
End Sub
End Class


Of course, you'd have to take care of calling CheckSecurityAccess() every time you login/out of your app, but you get the picture. (you can have the principal take care of that)
Also, you might have to go a slightly different way if running a web app (like storing an instance of a similar class in session or something like that).

You could also store similar properties in your identity object if it suits you better (but you'll end up doing a lot of type checking if you go that route).

Andrés

Copyright (c) Marimer LLC