Re: Creation of Proxy objects very slow

76 views
Skip to first unread message

Dominik

unread,
Oct 28, 2012, 11:10:19 AM10/28/12
to castle-pro...@googlegroups.com
Adding profiling information



Am Sonntag, 28. Oktober 2012 13:32:52 UTC+1 schrieb Dominik:

Hi

I've got an issue trying to create proxied objects of my Data-Class. Trying to create the class and the interceptor independently for 500'000 objects shows basically no performance consumption (around 0.06 seconds). However the combination with a proxy class takes around 100 times longer (around 5.5 seconds). I can't figure out why the contruction is taking that much longer.


This happens for the following code:

''' <summary>
    ''' Interceptor zum sichern der Originalwerte
    ''' </summary>
    ''' <remarks>Der erste Zugriff auf ein Property, wird als Originalwert interpretiert</remarks>
    Public Class ValueTrackerInterceptor
        Implements Castle.DynamicProxy.IInterceptor, IValueTracker


        Private myisInit = True

        Private myOriginValues As New Dictionary(Of String, Object)
        'Private myValueChanged As Boolean = False
        'Private myColumninfo As Mapper.ColumnMappingInfo = Nothing

        Public Sub Intercept(invocation As Castle.DynamicProxy.IInvocation) Implements Castle.DynamicProxy.IInterceptor.Intercept

            Dim Prop As String = invocation.Method.Name
            If Prop.StartsWith("set_") Then
                Prop = Prop.Remove(0, 4)

                If Not myOriginValues.ContainsKey(Prop) Then
                    SyncLock myOriginValues
                        If Not myOriginValues.ContainsKey(Prop) Then
                            myOriginValues.Add(Prop, invocation.Arguments(0))
                        End If
                    End SyncLock
                End If

                invocation.Proceed()

            ElseIf Prop = "get_ValueChanged" Then
                invocation.ReturnValue = ValueChanged
            ElseIf Prop = "get_OriginValues" Then
                invocation.ReturnValue = OriginValues
            ElseIf Prop = "Reset" Then
                Reset()
            Else
                invocation.Proceed()
            End If
        End Sub

        Public ReadOnly Property OriginValues As System.Collections.Generic.IDictionary(Of String, Object) Implements IValueTracker.OriginValues
            Get
                SyncLock myOriginValues
                    Dim ret As Dictionary(Of String, Object) = New Dictionary(Of String, Object)(myOriginValues)
                    Return ret
                End SyncLock
            End Get
        End Property

        Public ReadOnly Property ValueChanged As Boolean Implements IValueTracker.ValueChanged
            Get
                SyncLock myOriginValues
                    Return myOriginValues.Count > 0
                End SyncLock
            End Get
        End Property

        Public Sub Reset() Implements IValueTracker.Reset
            SyncLock myOriginValues
                myOriginValues.Clear()
            End SyncLock
        End Sub
    End Class


Public Class ModelProxyFactory


        Private myGenerator As New Castle.DynamicProxy.ProxyGenerator()


        Private ReadOnly Property Generator As Castle.DynamicProxy.ProxyGenerator
            Get
                Return myGenerator
            End Get
        End Property

        ''' <summary>
        ''' Kontruktor verstecken
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub New()

        End Sub

        ''' <summary>
        ''' Cache für die bereits erstellten Proxies
        ''' </summary>
        ''' <remarks></remarks>
        Private OptionsCache As New Concurrent.ConcurrentDictionary(Of System.Type, Castle.DynamicProxy.ProxyGenerationOptions)()


        Private Shared Function getGenerationOptions(Target As Type) As Castle.DynamicProxy.ProxyGenerationOptions

            Dim Hook As GenerationHook = New GenerationHook(Target)
            Dim options As New Castle.DynamicProxy.ProxyGenerationOptions(Hook)

            Return options
        End Function

        Private ic As New ValueTrackerInterceptor()

        ''' <summary>
        ''' Gibt den Proxy für die angegebene Klasse zurück
        ''' </summary>
        ''' <typeparam name="TType"></typeparam>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function getProxy(Of TType As Class)() As TType

        
            Dim ret As TType = DirectCast(Generator.CreateClassProxy(GetType(TType), {GetType(IValueTracker)}, {ic}), TType)

            'DirectCast(ret, IValueTracker).isInit = False
            'Return ret

            Return ret
        End Function

        Private Shared ourInstance = New ModelProxyFactory

        Public Shared ReadOnly Property Instance As ModelProxyFactory
            Get
                Return ourInstance
            End Get
        End Property

    End Class

calling code:

' Startup-Proxy creation
        Dim tmp3 As Model.Origin = Core.Data.DAL.ModelProxy.ModelProxyFactory.Instance.getProxy(Of Timeseries.Model.Origin)()
        Dim tmp4 As Core.Data.DAL.ModelProxy.ValueTrackerInterceptor = Nothing

        watch.Start()
        For n = 1 To 500000

            tmp4 = New Core.Data.DAL.ModelProxy.ValueTrackerInterceptor()
            tmp3 = New Model.Origin
        Next
        watch.Stop()
        MessageBox.Show(watch.ElapsedMilliseconds / 1000)

        watch.Reset()
        watch.Start()
        For n = 1 To 500000
            tmp3 = Core.Data.DAL.ModelProxy.ModelProxyFactory.Instance.getProxy(Of Timeseries.Model.Origin)()
        Next

        watch.Stop()
        MessageBox.Show(watch.ElapsedMilliseconds / 1000)


Profiling.png

Dominik

unread,
Nov 7, 2012, 3:25:33 PM11/7/12
to castle-pro...@googlegroups.com
I was asked to provide a "demo". Here you go.

I hope someone is able to help me now ;-)


ProxyTester.zip

James Curran

unread,
Nov 7, 2012, 3:59:11 PM11/7/12
to Castle Project Users
I haven't looked at your code, but I remember that on the one project where I used the Dynamic Proxy, it was very easy to defeat the internal caching.   As I recall, there's a bunch of different classes which could be used to override class members.  They can be made as one big class, but if you do, the cache never finds a hit.

Truth,
    James


On Wed, Nov 7, 2012 at 3:25 PM, Dominik <dominik_...@gmx.ch> wrote:
I was asked to provide a "demo". Here you go.

I hope someone is able to help me now ;-)



--
You received this message because you are subscribed to the Google Groups "Castle Project Users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/castle-project-users/-/VB543kPWwKoJ.

To post to this group, send email to castle-pro...@googlegroups.com.
To unsubscribe from this group, send email to castle-project-u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/castle-project-users?hl=en.

Reply all
Reply to author
Forward
0 new messages