Author Topic: Speed Improvement  (Read 13891 times)

0 Members and 1 Guest are viewing this topic.

DBARANAS

  • Guest
Speed Improvement
« on: July 25, 2007, 01:42:57 PM »
My apps design is split into 3 major sections.

1] The top section gets persisted and holds simple parameters that define the sub assemblies in a Building Model.

2] The middle section creates, moves, deletes, etc, my objects based on project parameters, These objects are contained in generic lists. It boils down to just lists of solids, polylines, lines, tables, and mtexts.

3] The last section is just a few methods to open up transactions and iterate the generic lists and have Acad do work.

This scheme works quite well until the model gets bigger, On a 2 year old box with 1G Ram and a $100 NVidia card it takes about 7-10 seconds to create ~500 solids.

When I profile I see that 95% of the time is spent in just 1 method [3] ...example below

What I am thinking about doing is getting few these methods [3] that interface to Acad in their own native class and wrap it and call it from my managed code in the hopes that Native Arx is quicker than Net Arx.

This would be a big learning curve for unkown benefit if any, Any thoughts are appreciated



Code: [Select]
   

Friend Shared Sub DrawEntities()

        Dim db As AcDb.Database = AcDb.HostApplicationServices.WorkingDatabase
        Dim tr As AcDb.Transaction = db.TransactionManager.StartTransaction()
        Dim dl As AcAs.DocumentLock = AcAp.DocumentManager.MdiActiveDocument.LockDocument()
        Dim bt As AcDb.BlockTable = DirectCast(tr.GetObject(db.BlockTableId, _
        AcDb.OpenMode.ForWrite, True), AcDb.BlockTable)
        Dim br As AcDb.BlockTableRecord = DirectCast(tr.GetObject(bt(AcDb.BlockTableRecord.ModelSpace), _
        AcDb.OpenMode.ForWrite, False), AcDb.BlockTableRecord)

        For Each Line As AcDbLine In Lines
            If Not Line.ID.Exists Then
                'Create AcDb Entity
                Dim en As New AcDb.Line(New AcGe.Point3d(0, 0, 0), New AcGe.Point3d(5, 0, 0))
                en.Color = AcCm.Color.FromColor(Line.Color)
                'Rotate Around Z Axis
                en.TransformBy(AcGe.Matrix3d.Rotation(Rad(Line.Rotation), _
                New AcGe.Vector3d(0, 0, 1), New AcGe.Point3d(0, 0, 0)))
                'Move in ModelSpace
                Dim _Matrix3d As AcGe.Matrix3d = AcGe.Matrix3d.Displacement(New AcGe.Vector3d( _
                Line.Origin.X + (Math.Cos(Rad(Line.Angle)) * Line.Position.X), _
                Line.Origin.Y - (Math.Sin(Rad(Line.Angle)) * Line.Position.X), _
                Line.Position.Z))
                en.TransformBy(en.Ecs.PostMultiplyBy(_Matrix3d))
                'Add Entity to AcDb
                br.AppendEntity(en)
                tr.AddNewlyCreatedDBObject(en, True)
                'Update FwHr Entity
                Line.ID.AcDbHandle = en.ObjectId.Handle.Value.ToString()
                Line.ID.Exists = True
            End If
        Next

        For i As Integer = 0 To PolyLines.Count - 1
            If Not PolyLines(i).ID.Exists Then
                'Create AcDb Entity
                Dim PointCol As New AcGe.Point3dCollection
                For j As Integer = 0 To PolyLines(i).Points.Count - 1
                    PointCol.Add(New AcGe.Point3d(PolyLines(i).Points(j).XYZ))
                Next
                Dim en As New AcDb.Polyline3d(AcDb.Poly3dType.SimplePoly, PointCol, True)
                en.Visible = PolyLines(i).IsVisible
                en.Color = AcCm.Color.FromColor(PolyLines(i).Color)
                Select Case PolyLines(i).IsOnWCS
                    'Baselines are drawn in the WCS so they don't move and rotate
                    Case False
                        'Rotate Around Z Axis
                        en.TransformBy(AcGe.Matrix3d.Rotation(Rad(PolyLines(i).Rotation), _
                        New AcGe.Vector3d(0, 0, 1), New AcGe.Point3d(0, 0, 0)))
                        'Move in ModelSpace
                        Dim _Matrix3d As AcGe.Matrix3d = AcGe.Matrix3d.Displacement(New AcGe.Vector3d( _
                        PolyLines(i).Origin.X + (Cos(Rad(PolyLines(i).Angle)) * PolyLines(i).Position.X), _
                        PolyLines(i).Origin.Y - (Sin(Rad(PolyLines(i).Angle)) * PolyLines(i).Position.X), _
                        PolyLines(i).Position.Z))
                        en.TransformBy(en.Ecs.PostMultiplyBy(_Matrix3d))
                        en.List()
                End Select
                'Add Entity to AcDb
                br.AppendEntity(en)
                tr.AddNewlyCreatedDBObject(en, True)
                'Update FwHr Entity
                PolyLines(i).ID.AcDbHandle = en.ObjectId.Handle.Value.ToString()
                PolyLines(i).ID.Exists = True
            End If
        Next

        For i As Integer = 0 To Solids.Count - 1
            If Not Solids(i).ID.Exists Then
                Dim en As AcDb.Solid3d = Nothing
                Dim BasePointCol As New AcGe.Point3dCollection
                For j As Integer = 0 To Solids(i).Points.Count - 1
                    BasePointCol.Add(New AcGe.Point3d(Solids(i).Points(j).XYZ))
                Next
                Dim Polyline3d As AcDb.Polyline3d = New AcDb.Polyline3d(AcDb.Poly3dType.SimplePoly, BasePointCol, True)
                'Create Region
                Dim ColPoly As AcDb.DBObjectCollection = New AcDb.DBObjectCollection()
                Dim ColRegion As AcDb.DBObjectCollection = New AcDb.DBObjectCollection()
                ColPoly.Add(Polyline3d)
                ColRegion = AcDb.Region.CreateFromCurves(ColPoly)
                Dim Region As AcDb.Region = DirectCast(ColRegion(0), AcDb.Region)
                ColPoly.Dispose()
                ColRegion.Dispose()
                Polyline3d.Dispose()
                'Create AcDb Entity
                en = New AcDb.Solid3d()
                en.Extrude(Region, Solids(i).Extrude, 0)
                Region.Dispose()
                en.Color = AcCm.Color.FromColor(Solids(i).Color)

                'Union Solids if needed
                If Solids(i).AddRegions.Count > 0 Then
                    Dim AddPointCol As New AcGe.Point3dCollection
                    For j As Integer = 0 To Solids(i).AddRegions.Count - 1
                        'Get Union Points
                        For k As Integer = 0 To Solids(i).AddRegions.Item(j).Points.Count - 1
                            AddPointCol.Add(New AcGe.Point3d(Solids(i).AddRegions(j).Points(k).XYZ))
                        Next
                        'Create Union Region
                        Dim AddPolyline3d As AcDb.Polyline3d = New AcDb.Polyline3d(AcDb.Poly3dType.SimplePoly, AddPointCol, True)
                        Dim AddPoly As AcDb.DBObjectCollection = New AcDb.DBObjectCollection()
                        Dim AddRegion As AcDb.DBObjectCollection = New AcDb.DBObjectCollection()
                        AddPoly.Add(AddPolyline3d)
                        AddRegion = AcDb.Region.CreateFromCurves(AddPoly)
                        Dim AcDbAddRegion As AcDb.Region = DirectCast(AddRegion(0), AcDb.Region)
                        'Create Union Solid
                        Dim AddSolid As New AcDb.Solid3d
                        AddSolid.Extrude(AcDbAddRegion, Solids(i).AddRegions(j).Extrude, 0)
                        AddSolid.Color = AcCm.Color.FromColor(Solids(i).AddRegions(j).Color)
                        'Union Solid
                        en.BooleanOperation(AcDb.BooleanOperationType.BoolUnite, AddSolid)
                        AcDbAddRegion.Dispose()
                        AddRegion.Dispose()
                        AddPointCol.Clear()
                    Next
                    AddPointCol.Dispose()
                End If

                'Subtract Solids if needed
                If Solids(i).SubtractRegions.Count > 0 Then
                    Dim MinusPointCol As New AcGe.Point3dCollection
                    For j As Integer = 0 To Solids(i).SubtractRegions.Count - 1
                        'Get Minus Points
                        For k As Integer = 0 To Solids(i).SubtractRegions.Item(j).Points.Count - 1
                            MinusPointCol.Add(New AcGe.Point3d(Solids(i).SubtractRegions(j).Points(k).XYZ))
                        Next
                        'Create Minus Region
                        Dim MinusPolyline3d As AcDb.Polyline3d = New  AcDb.Polyline3d(AcDb.Poly3dType.SimplePoly, MinusPointCol, True)
                        Dim MinusPoly As AcDb.DBObjectCollection = New AcDb.DBObjectCollection()
                        Dim MinusRegion As AcDb.DBObjectCollection = New AcDb.DBObjectCollection()
                        MinusPoly.Add(MinusPolyline3d)
                        MinusRegion = AcDb.Region.CreateFromCurves(MinusPoly)
                        Dim AcDbSubRegion As AcDb.Region = DirectCast(MinusRegion(0), AcDb.Region)
                        'Create Minus Solid
                        Dim MinusSolid As New AcDb.Solid3d
                        MinusSolid.Extrude(AcDbSubRegion, Solids(i).SubtractRegions(j).Extrude, 0)
                        MinusSolid.Color = AcCm.Color.FromColor(Solids(i).SubtractRegions(j).Color)
                        'Subtract Solid
                        en.BooleanOperation(AcDb.BooleanOperationType.BoolSubtract, MinusSolid)
                        AcDbSubRegion.Dispose()
                        MinusRegion.Dispose()
                        MinusPointCol.Clear()
                    Next
                    MinusPointCol.Dispose()
                End If

                'Color Faces
                If Solids(i).ID.Description = g.c.Wall.PLATE_TOP_TOP Then
                    Dim ids As AcDb.ObjectId() = New AcDb.ObjectId(0) {}
                    Select Case Solids(i).Angle
                        Case g.c.FRONT, g.c.MINUS_FRONT
                            Dim Outside As New AcDb.SubentityId(AcDb.SubentityType.Face, 4)
                            Dim OutsidePath As New AcDb.FullSubentityPath(ids, Outside)
                            en.SetSubentityColor(Outside, AcCm.Color.FromColor(System.Drawing.Color.Green))
                            Dim Inside As New AcDb.SubentityId(AcDb.SubentityType.Face, 2)
                            Dim InsidePath As New AcDb.FullSubentityPath(ids, Inside)
                            en.SetSubentityColor(Inside, AcCm.Color.FromColor(System.Drawing.Color.Red))
                        Case g.c.BACK
                            Dim Outside As New AcDb.SubentityId(AcDb.SubentityType.Face, 2)
                            Dim OutsidePath As New AcDb.FullSubentityPath(ids, Outside)
                            en.SetSubentityColor(Outside, AcCm.Color.FromColor(System.Drawing.Color.Green))
                            Dim Inside As New AcDb.SubentityId(AcDb.SubentityType.Face, 4)
                            Dim InsidePath As New AcDb.FullSubentityPath(ids, Inside)
                            en.SetSubentityColor(Inside, AcCm.Color.FromColor(System.Drawing.Color.Red))
                        Case g.c.LEFT
                            Dim Outside As New AcDb.SubentityId(AcDb.SubentityType.Face, 4)
                            Dim OutsidePath As New AcDb.FullSubentityPath(ids, Outside)
                            en.SetSubentityColor(Outside, AcCm.Color.FromColor(System.Drawing.Color.Red))
                            Dim Inside As New AcDb.SubentityId(AcDb.SubentityType.Face, 2)
                            Dim InsidePath As New AcDb.FullSubentityPath(ids, Inside)
                            en.SetSubentityColor(Inside, AcCm.Color.FromColor(System.Drawing.Color.Green))
                        Case g.c.RIGHT, g.c.MINUS_RIGHT
                            Dim Outside As New AcDb.SubentityId(AcDb.SubentityType.Face, 2)
                            Dim OutsidePath As New AcDb.FullSubentityPath(ids, Outside)
                            en.SetSubentityColor(Outside, AcCm.Color.FromColor(System.Drawing.Color.Red))
                            Dim Inside As New AcDb.SubentityId(AcDb.SubentityType.Face, 4)
                            Dim InsidePath As New AcDb.FullSubentityPath(ids, Inside)
                            en.SetSubentityColor(Inside, AcCm.Color.FromColor(System.Drawing.Color.Green))
                    End Select
                End If

                Select Case Solids(i).IsOnWCS
                    'Baselines are drawn in the WCS so they don't move and rotate
                    Case False
                        'Rotate Around Z Axis
                        en.TransformBy(AcGe.Matrix3d.Rotation(Rad(Solids(i).Rotation), New AcGe.Vector3d(0, 0, 1), New AcGe.Point3d(0, 0, 0)))
                        'Move in ModelSpace
                        Dim _Matrix3d As AcGe.Matrix3d = AcGe.Matrix3d.Displacement(New AcGe.Vector3d(Solids(i).Origin.XYZ))
                        en.TransformBy(en.Ecs.PostMultiplyBy(_Matrix3d))
                End Select

                'Add Entity to AcDb
                br.AppendEntity(en)
                tr.AddNewlyCreatedDBObject(en, True)
                'Update FwHr Entity
                Solids(i).ID.AcDbHandle = en.ObjectId.Handle.Value.ToString
                Solids(i).ID.Exists = True
                Solids(i).Centroid = en.MassProperties.Centroid.ToArray
                Solids(i).Weight = en.MassProperties.Volume * g.c.Weight.SPF

                If Solids(i).IsSelectable Then
                    'Add xData to AcDb Entity
                    Dim xRec As New AcDb.Xrecord()
                    xRec.Data = New AcDb.ResultBuffer( _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Beam), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.BeamPocket), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Blocking), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Building), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Description), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Door), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.DoubleStud), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.FireStopping), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.FloorSheeting), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Item), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Joist), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Panel), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Partition), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Post), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Project), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.RimJoist), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Slab), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Stair), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Storey), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Strapping), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Wall), _
                    New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Window))
                    en.CreateExtensionDictionary()
                    Dim SolidExtDict As AcDb.DBDictionary = DirectCast(tr.GetObject(en.ExtensionDictionary(), _
                    AcDb.OpenMode.ForWrite, False), AcDb.DBDictionary)
                    SolidExtDict.SetAt("EntityData", xRec)

                    'Add Entity to AcDb
                    tr.AddNewlyCreatedDBObject(xRec, True)
                End If
            End If
        Next

        For i As Integer = 0 To MTexts.Count - 1
            If Not MTexts(i).ID.Exists Then
                'Create AcDb Entity
                Dim en As New AcDb.MText()
                en.Contents = MTexts(i).Value
                en.TextHeight = g.c.TEXT_HEGHT
                en.Color = AcCm.Color.FromColor(MTexts(i).Color)

                'Rotate Around Z Axis
                en.TransformBy(AcGe.Matrix3d.Rotation(Rad(MTexts(i).Angle), New AcGe.Vector3d(0, 0, 1), New AcGe.Point3d(0, 0, 0)))
                'Move in ModelSpace
                Dim MatrixA As AcGe.Matrix3d = AcGe.Matrix3d.Displacement(New AcGe.Vector3d( _
                MTexts(i).Origin.X + (Cos(Rad(MTexts(i).Angle)) * MTexts(i).Position.X), _
                MTexts(i).Origin.Y + (Sin(Rad(MTexts(i).Angle)) * MTexts(i).Position.X), _
                MTexts(i).Position.Z))
                en.TransformBy(en.Ecs.PostMultiplyBy(MatrixA))

                Dim MatrixB As AcGe.Matrix3d = AcGe.Matrix3d.Displacement(New AcGe.Vector3d( _
                -Sin(Rad(MTexts(i).Angle)) * MTexts(i).Position.Y, _
                Cos(Rad(MTexts(i).Angle)) * MTexts(i).Position.Y, _
                0))
                en.TransformBy(en.Ecs.PostMultiplyBy(MatrixB))

                'Add Entity to AcDb
                br.AppendEntity(en)
                tr.AddNewlyCreatedDBObject(en, True)
                'Update FwHr Entity
                MTexts(i).ID.AcDbHandle = en.ObjectId.Handle.Value.ToString()
            End If
        Next

        dl.Dispose()
        tr.Commit()
        tr.Dispose()

        Project.CommandLineTimeStamp("DrawingAids.DrawEntities" & " -Count [" & Solids.Count.ToString & "]")

    End Sub




It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8718
  • AKA Daniel
Re: Speed Improvement
« Reply #1 on: July 26, 2007, 09:33:44 PM »
Hi Dave,

Your code looks very well written. I don’t how much of a performance gain you would get by porting this method to C++, It’s kind of the “don’t know until you try” thing. I would suspect it would be only a few percent. It certainly is possible to stick this in a mixed managed / unmanaged assembly, but probably isn’t a trivial task. What version of AutoCAD it this intended for?

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: Speed Improvement
« Reply #2 on: July 26, 2007, 10:07:16 PM »
besides, 7-10 sec's for 500 solids with mod's/xform's isn't that bad, I'd hate to do it by hand ;)
I'm guessing the objects (such as lines) you are getting the data from your own object classes, if that is the case, passing your lists of objects to arx to do the xform and db stuff 'may' save you considerable time, but as Daniel pointed out I'm not sure it's worth it.
Nice job!
« Last Edit: July 26, 2007, 10:08:39 PM by MickD »
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

DBARANAS

  • Guest
Re: Speed Improvement
« Reply #3 on: July 27, 2007, 01:05:56 AM »
Hi Daniel, Mick

Yes everything is done in my classes and I end up with generic lists of my entities which have enough stuff in them to hand over to Acad so it can make everything blindly and only in 1 or 2 transactions. I found they each eat up time so that's why I did it that way.

Every time something is changed by the user the assembly in question is completely destroyed and rebuilt. This is because I am doing some weird things like adjusting everything based on weekly lumber prices, truck sizes, bad foundations, people changing their minds, etc, etc. I never know exactly how many or what size things will end up being until the model builds/rebuilds itself.

Being 100% parametric and with no drafting going on I sometimes have to destroy and rebuild a building which can contain >3000 entities.

Seeing as most everything between me and Acad goes on in that last method, it should be worth learning to write a C++ dll that does what that method does and see what happens. I have 3 similar methods like that one and thats it.

I hope that between http://arxdummies.blogspot.com/2006/03/autocad-2007.html, C++-CLI Standard.pdf, and the Adesk Object Arx group I can figure something out and speed things up

I am still in 2007, in 2008 something broke with the PropertyGrid on a Palette not showing items in dropdowns when using type converters....another battle for later.




MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: Speed Improvement
« Reply #4 on: July 27, 2007, 01:37:40 AM »
Just a thought, could you create a matrix and store it on the object that contains the values and just pass these values to the acad matrix method for a one time xform. If I remember correctly you can build a matrix by passing in an array of values to initialise the matrix, pass it in and 'doit'. This may save you reading, sorting and manipulating you objects as much as a matrix can hold both rotation and translation in the one matrix. It will involve a bit of math on your part but the drawing/rebuilding may be quicker??
hth.
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

DBARANAS

  • Guest
Re: Speed Improvement
« Reply #5 on: July 27, 2007, 04:24:43 AM »
Just a thought, could you create a matrix and store it on the object that contains the values and just pass these values to the acad matrix method for a one time xform. If I remember correctly you can build a matrix by passing in an array of values to initialise the matrix, pass it in and 'doit'. This may save you reading, sorting and manipulating you objects as much as a matrix can hold both rotation and translation in the one matrix. It will involve a bit of math on your part but the drawing/rebuilding may be quicker??
hth.

I did a quick test by stripping out xforms, subtracting, unions. Just get everything into modelspace at 0,0,0.

On ~1000 items all unstripped I average 13 to 16 secs. On the stripped version it is a very consistant 
10.500 sec (+/- 50mSec). So it seems that overhead is costing ~25% more....not too much for all the work it's doing.

That was a good idea and it shows that most of the overhead is spent just creating things without doing anything else.






LE

  • Guest
Re: Speed Improvement
« Reply #6 on: July 27, 2007, 01:04:19 PM »
When I profile I see that 95% of the time is spent in just 1 method [3] ...example below

(I am new to C#)

What did you use for that?

Have you seen or tried ANTS Profiler? by red-gate - I have seen the ads in the codeproject.com web site.

DBARANAS

  • Guest
Re: Speed Improvement
« Reply #7 on: July 28, 2007, 12:39:33 AM »
When I profile I see that 95% of the time is spent in just 1 method [3] ...example below

(I am new to C#)

What did you use for that?

Have you seen or tried ANTS Profiler? by red-gate - I have seen the ads in the codeproject.com web site.


This is a simple counter I think I might have found on codeproject.com and changed a bit ...can't remember. I tried ANTS before, I use this because it's quick and dirty and all I really need.

Running the code below produced the following results. It averages around 40 uSecs just to make the counter write to the command line compared with a few mSecs for most commands and functions to execute, so I get a pretty good idea how long things are really taking.


Code: [Select]
       Project.CommandLineTimeStamp("DrawingAids.DrawEntities" & " -Count [" & Solids.Count.ToString & "]")
        Project.CommandLineTimeStamp("Test Counter")
        Project.CommandLineTimeStamp("Test Counter")
        Project.CommandLineTimeStamp("Test Counter")
        Project.CommandLineTimeStamp("Test Counter")
        Project.CommandLineTimeStamp("Test Counter")
        Project.CommandLineTimeStamp("Test Counter")
        Project.CommandLineTimeStamp("Test Counter")
        Project.CommandLineTimeStamp("Test Counter")
        Project.CommandLineTimeStamp("Test Counter")
        Project.CommandLineTimeStamp("Test Counter")
        Project.CommandLineTimeStamp("Test Counter")
        Project.CommandLineTimeStamp("Test Counter")
        Project.CommandLineTimeStamp("Test Counter")
        Project.CommandLineTimeStamp("Test Counter")

Code: [Select]
    Public Function CommandLineTimeStamp( _
    ByVal Description As String) _
    As Boolean

        Dim ed As AcEd.Editor = AcAp.DocumentManager.MdiActiveDocument.Editor

        ed.WriteMessage( _
        MsVb.Chr(10) & _
        Description _
        & " [" & (TIMER.Peek() / CType(1000, Single)).ToString() & "]" & MsVb.Chr(10))

        TIMER.Reset()

        Return True

    End Function

Code: [Select]
Public NotInheritable Class StopWatch

    Private Declare Ansi Function QueryPerformanceCounter Lib "kernel32.dll" (ByRef x As Long) As Integer
    Private Declare Ansi Function QueryPerformanceFrequency Lib "kernel32.dll" (ByRef x As Long) As Integer
    Private _Frequency As Long
    Private _Increment As Long
    Private _StartTime As Long
    Public Sub New()

        Frequency = GetFrequency()
        Reset()

    End Sub
    Public Function Duration() _
    As Long

        Return CType((((GetValue() - StartTime) / CType(Frequency, Double)) * 1000000), Long)

    End Function
    Private Function GetFrequency() As Long

        Dim ret As Long = 0
        If QueryPerformanceFrequency(ret) = 0 Then
            Throw New NotSupportedException("Error while querying the performance counter frequency.")
        End If
        Return ret

    End Function
    Private Function GetValue() As Long

        Dim ret As Long = 0
        If QueryPerformanceCounter(ret) = 0 Then
            Throw New NotSupportedException("Error while querying the high-resolution performance counter.")
        End If
        Return ret

    End Function
    Public Function Peek() _
    As Long

        Return CType((((GetValue() - StartTime) / CType(Frequency, Double)) * 1000000), Long)

    End Function
    Public Sub Reset()

        StartTime = GetValue()

    End Sub
    Private Property Frequency() As Long

        Get
            Return _Frequency
        End Get
        Set(ByVal Value As Long)
            _Frequency = Value
        End Set

    End Property
    Private Property Increment() As Long

        Get
            Return _Increment
        End Get
        Set(ByVal Value As Long)
            _Increment = Value
        End Set

    End Property
    Private Property StartTime() As Long

        Get
            Return _StartTime
        End Get
        Set(ByVal Value As Long)
            _StartTime = Value
        End Set

    End Property

End Class

« Last Edit: August 02, 2007, 10:42:09 AM by Dave Baranas »

Glenn R

  • Guest
Re: Speed Improvement
« Reply #8 on: July 31, 2007, 05:21:37 AM »
Have you tried NOT using the transaction mechanism/paradigm and use the traditional open/close ARX method?

ie. BlockTableRecord btr = ModelSpaceBlockTableRecordObjectId.Open(yada, yada);

// Dome some funky mojo here

btr.Close();

Using the open/close model can gain you significant speed improvements, however, you have to REALLY REALLY carefull to make sure you close everything you open...as you do in ARX.

Just some thoughts.

Cheers,
Glenn.


DBARANAS

  • Guest
Re: Speed Improvement
« Reply #9 on: August 01, 2007, 12:19:15 AM »
Have you tried NOT using the transaction mechanism/paradigm and use the traditional open/close ARX method?

Using the open/close model can gain you significant speed improvements, however, you have to REALLY REALLY carefull to make sure you close everything you open...as you do in ARX.


Thanks Glenn

I was not able to get at the bt/btr without using tr.GetObject.........
I cannot find a br.open method just a close method and Acad warns it is obsoleted and to use a tr instead.

Do you have any C# code of doing this you could show?....
This is .Net and not COM you mean with the open/close way right......???

After a weekend in the Arx Samples it seems the "F:\ObjectARX 2007\samples\entity\polysamp\" is a good starting place if I have go the .Net/Arx way.

I am thinking about having the Arx project reference the Net project so I can just pass over the Lists and have the DrawEntities method done (C++) over there.....and return the list back to the managed side when the work is done.

This brings up concerns about what kind overhead can occur when passing big lists across net/native boundaries .. I am getting the feeling that this might be really getting done via COM... :-(




It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8718
  • AKA Daniel
Re: Speed Improvement
« Reply #10 on: August 01, 2007, 02:31:32 AM »
Dave, if you think you may need the functionality of both .NET and Native C/C++, you should consider using a mixed managed/unmanaged dll. Of course this would mean using C++ & C++/CLI. The good thing is that you can use a translator to move your existing VB code to C++/CLI. To move your “List” between the managed and unmanaged worlds, you may be able to use a ResultBuffer / *resbuf since it already does the memory pinning and type conversions.

Just a thought

Glenn R

  • Guest
Re: Speed Improvement
« Reply #11 on: August 01, 2007, 06:00:57 AM »
Dave,
I'm actually out of the country at the moment, so I don't have a my laptop handy.

You don't open off an object - you open off an ObjectId, so for instance:

Database db = HostApplicationServices.WorkingDatabase;

BlockTable bt = db.BlockTableId.Open(OpenMode.ForRead, false) as BlockTable;
// Do some mojo
// Don't forget to close
bt.Close();

Then go for a particular blocktablerecord by using the blocktable's indexer. I would show it, but the keyboard I'm using at the moment, is faling to recognise the right square bracket.

This is all off the top of my head, however I think you get the idea.

Cheers,
Glenn.

DBARANAS

  • Guest
Re: Speed Improvement
« Reply #12 on: August 02, 2007, 06:41:15 AM »
Dave,

You don't open off an object - you open off an ObjectId, so for instance:


I was able to get these this way.

Code: [Select]
        Dim bt As AcDb.BlockTable = DirectCast(db.BlockTableId.GetObject(OpenMode.ForWrite), BlockTable)
        Dim br As AcDb.BlockTableRecord = DirectCast(bt.Item(AcDb.BlockTableRecord.ModelSpace.ToString).GetObject( _
        OpenMode.ForWrite, True), BlockTableRecord)


Then I used the bt.Add(br)

This only half works if a transaction has not been commented out even though I am trying to go around using it. Unless I use tr.AddNewlyCreatedDBObject it won't show up in modelspace.

If I don't have a transaction going bt is null and I can't get to br through it.

Another idea is to find something in the Arx samples...maybe ..samples\entity\polysamp\ and put it in a loop and see how much Arx is faster.....and if so then going C++ mixed Arx/Net might be the only way left.

LE

  • Guest
Re: Speed Improvement
« Reply #13 on: August 02, 2007, 10:52:38 AM »
Another idea is to find something in the Arx samples...maybe ..samples\entity\polysamp\ and put it in a loop and see how much Arx is faster.....and if so then going C++ mixed Arx/Net might be the only way left.

Dave;

Most of my functions now are in C++ and with ARX, never had done any salad mixing of managed-unmanaged code... but going to that place just to improve a 7-10 secs? do not know...  :roll:

Here is attached a function in C++ that does a summation of list of lists and a sample list, maybe will provide an idea of the average timing that takes to process a long list inside of a C++ function and in AutoCAD... (the source code of summation() is in the ARX forum)

Load the list from the VLIDE and then in the command line:

Command: (summation lst)

HTH

Glenn R

  • Guest
Re: Speed Improvement
« Reply #14 on: August 04, 2007, 05:41:59 AM »
Dave,

DO NOT mix transactions and the open/close paradigm - you will get unpredictable results. Use one or the other, but not both.

Code: [Select]
// get the current dbase
Database db = HostApplicationServices.WorkingDatabase;

// get the block table
BlockTable bt = db.BlockTableId.Open(OpenMode.ForRead, false) as BlockTable;
if (bt == null)
    return;

// get the modelspace block as an example
ObjectId modelBtrId = bt[BlockTableRecord.ModelSpace];
BlockTableRecord modelBtr = modelBtrId.Open(OpenMode.ForWrite, false) as BlockTableRecord;
if (modelBtr == null)
    return;

// Close blocktable as we don't need it anymore
bt.Close();

// Create a line
Line pLine = new Line();
// Set some properties here...
// blah blah

// Add it to modelspace
modelBtr.AddNewlyCreatedDBObject(pLine);      //can't off the top of my head remember the method name but pretty sure it's AddNewlyCreatedDBObject...

// VERY VERY important - always close what you open
modelBtr.Close();


That should give you the idea. It's essentailly the same thing I posted previously.
Remeber this is all off the top of my head, but I'm sure somebody will correct me if I'm wrong.

Glenn.
« Last Edit: August 04, 2007, 05:43:31 AM by Glenn R »