Author Topic: Speed up code  (Read 5199 times)

0 Members and 1 Guest are viewing this topic.

T.Willey

  • Needs a day job
  • Posts: 5251
Speed up code
« on: January 16, 2015, 01:45:21 PM »
The code I am working on is nearly done, but for some reason it is taking an extremely long time to process one portion of the code.  The first section of my code is a recursive process, that pretty much equals the speed of the autocad command, but does more.  The next part of the code takes up to 20 minutes to complete, which is way longer than doing it manually.  If I run my code without the first section, then the code completes in a timely manner.  I cannot do the recursive portion another way, and I have tried to read everything about freeing memory and releasing objects and disposing objects, but no matter what I try the time does not lessen.  I tried putting my first section of code in it's own method, thinking that would speed up the second section, but that did nothing either.

The first potion is exploding blocks.  The second potion is copying certain items to a new database ( WBlockCloneObjects ).

I am at my wits end, and would appreciate any tidbits of information anyone has on options I could try to speed up my code.

Thanks in advance.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: Speed up code
« Reply #1 on: January 16, 2015, 02:31:43 PM »
Just off the top of my head, are you re-using your transactions?
That is, I often pass around a transaction to use in other methods to create and add things to the db instead of spinning up a new one in each method.
"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

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Speed up code
« Reply #2 on: January 16, 2015, 02:41:54 PM »
Yes I do.  That was the first change I did to try and speed things up, after reading in the Arx doc's to not have nested transactions in recursive methods.  I do not pass them to other methods though.  If that could help, then I could change those also to use just the single transaction.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

Cathy

  • Guest
Re: Speed up code
« Reply #3 on: January 16, 2015, 02:47:57 PM »
*grasping at straws and trying to isolate the problem*
Is it possible to run the second (slow) portion without running the first? 

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Speed up code
« Reply #4 on: January 16, 2015, 02:54:42 PM »
To a point it is, and I have done that.  This results in a great improvement in speed which is comparable to core commands.  But my customer wants it in a single command, which I feel it needs to be also.  So, I need to figure out how I can get the same speed for the second part of the code while the first part still does it's job.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: Speed up code
« Reply #5 on: January 16, 2015, 05:49:20 PM »
Maybe try a 'save' on the db to free up some memory in between the 2 methods?
"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

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Speed up code
« Reply #6 on: January 16, 2015, 06:05:29 PM »
I do not want to keep anything that I do to the first drawing, which is what the first section does.

I can try saving it to a temp location and see if that will help speed up the code.  If so, then maybe I can use something like it in production.

Thanks.  Off to run some tests.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8707
  • AKA Daniel
Re: Speed up code
« Reply #7 on: January 16, 2015, 06:35:50 PM »
How's your memory footprint? Maybe you can run...
GC.Collect();
GC.WaitForPendingFinalizers();
….Between the two operations

maybe don’t use transactions at all if everything is OpenMode.ForRead

Code: [Select]

       static void TheGreatExpoder(ObjectId entid, DBObjectCollection explodedObjects)
        {
            using (Entity ent = entid.Open(OpenMode.ForRead) as Entity)
            {
                if (ent != null)
                {
                    TheTinyExpoder(ent, explodedObjects);
                }
            }
        }
 


T.Willey

  • Needs a day job
  • Posts: 5251
Re: Speed up code
« Reply #8 on: January 16, 2015, 07:15:39 PM »
Thanks for the options guys, but neither one of those worked.

Daniel,

I am adding items to the database, as my explode works like bursting, so no information from attributes are lost.  So I think I need a transaction.  Also I am editing the item after they are exploded.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Speed up code
« Reply #9 on: January 17, 2015, 01:10:16 AM »
I just tried to save the drawing to a temp location.  Create an array of handles of the entities to be copied to the new drawing.  I then close the original drawing, without saving.  Create two new databases in memory, copy the entities whose handles are in the list to the new database.  It still takes about 20 minutes for this process to finish.

Memory in task manager:
Original drawing open = 460,000k
During first portion, steadily grows to 1,5000,000k
Close of drawing = 350,000k
Create/open databases = 500,000k
Copying grows slowly to 1,4000,000k
Opening new drawing = 1,250,000k


Maybe it just is what it is, as I opened the saved drawing and ran the program, where only the second section is really called, and it still too 15 minutes.  I will confirm this tomorrow, as it is past my bed time here.

Thanks again everyone.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8707
  • AKA Daniel
Re: Speed up code
« Reply #10 on: January 17, 2015, 03:40:52 AM »
IO hit? I wonder if disableUndoRecording on the destination database, would help in this case

nekitip

  • Guest
Re: Speed up code
« Reply #11 on: January 17, 2015, 05:32:12 AM »
Just off the top of my head, are you re-using your transactions?
That is, I often pass around a transaction to use in other methods to create and add things to the db instead of spinning up a new one in each method.
I always pass transaction object to other methods, however I once read that you don't need to do this if you have something like:
Open transaction
(call other methods, do not pass transaction)
commit
And then in other methods, just use open (without calling something like top transaction).
I can't find this now, since I forgot to write this down, and kept passing transaction object for compatibility...

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Speed up code
« Reply #12 on: January 17, 2015, 10:41:39 AM »
IO hit? I wonder if disableUndoRecording on the destination database, would help in this case

This didn't seem to do anything.

When I used the wblock command, the memory usage got to around 2,400,000k and it took under a minute to execute.

Edit:  Even using this small code, it took too long ( I stopped it after 6 minutes ).  Granted there are a tonne of objects being select, I would think the code should be close to the speed that the wblock command accomplishes it's task in.
Code: [Select]
        [ CommandMethod( "TestCopy", CommandFlags.Session ) ]
        public void CopyObjects () {
            Document doc = AcadApp.DocumentManager.MdiActiveDocument;
            using ( DocumentLock dlock = doc.LockDocument() )
            using ( Transaction trans = doc.TransactionManager.StartTransaction() )
            using ( Database db = doc.Database )
            using ( Database newDb = new Database( true, true ) ){
                PromptSelectionResult psr = doc.Editor.GetSelection();
                db.WblockCloneObjects( new ObjectIdCollection( psr.Value.GetObjectIds() ), getTableItem( newDb.BlockTableId, "*Model_Space" ),
                                        new IdMapping(), DuplicateRecordCloning.Ignore, false );
                newDb.SaveAs( @"c:\test\testcopy.dwg", DwgVersion.Current );
            }
        }

An aside:  I had to put in the using transaction, or the program would crash AutoCAD, even though I do not use it.  Just something to note for later.
« Last Edit: January 17, 2015, 11:28:42 AM by T.Willey »
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Speed up code
« Reply #13 on: January 17, 2015, 06:27:01 PM »
So I found an way.  I will fine tune it some, to figure out a good number for the max number of ObjectId's to copy at a time.  Right now it is set at 75000.  And now for the code.

Code: [Select]
[ CommandMethod( "TestCopy", CommandFlags.Session ) ]
public void CopyObjects () {
    try {
    Document doc = AcadApp.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;
    using ( DocumentLock dlock = doc.LockDocument() )
    using ( Transaction trans = doc.TransactionManager.StartTransaction() )
    using ( Database newDb = new Database( true, true ) )
    {
        PromptSelectionResult psr = doc.Editor.GetSelection();
        ObjectIdCollection copyIds = new ObjectIdCollection( psr.Value.GetObjectIds() );
        ObjectIdCollection tempIds = new ObjectIdCollection();;
        Int32 cnt = 0;
        Int32 max = 75000;
        foreach ( ObjectId oid in copyIds ) {
            tempIds.Add( oid );
            cnt++;
            if ( cnt == max ) {
                db.WblockCloneObjects( tempIds, aitrUtils.getTableItem( newDb.BlockTableId, "*Model_Space" ),
                                         new IdMapping(), DuplicateRecordCloning.Ignore, false );
                cnt = 0;
                tempIds.Clear();
            }
        }
        if ( cnt > 0 ) {
            db.WblockCloneObjects( tempIds, getTableItem( newDb.BlockTableId, "*Model_Space" ),
                                     new IdMapping(), DuplicateRecordCloning.Ignore, false );
        }
        newDb.SaveAs( @"c:\test\testcopy.dwg", DwgVersion.Current );
    }
    }
    catch ( Autodesk.AutoCAD.Runtime.Exception ex ) { MessageBox.Show( ex.ToString(), "Autocad" ); }
    catch ( System.Exception ex ) { MessageBox.Show( ex.ToString(), "System" ); }
}
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8707
  • AKA Daniel
Re: Speed up code
« Reply #14 on: January 17, 2015, 10:26:47 PM »
try newDb.DisableUndoRecording(), see if it makes a difference