Author Topic: Relative speed of SelectionSets and Iterating a DB.  (Read 11689 times)

0 Members and 1 Guest are viewing this topic.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #15 on: March 16, 2008, 09:38:12 AM »
nice coding  8-)

End eval...Process time: 0.0801152 Seconds for 923 records of 109993

Glenn R

  • Guest
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #16 on: March 16, 2008, 10:10:27 AM »
Dan,

I can't get the below to work on my machine, so can you give it a try...I think you see where I'm headed with it :)

Code - C#: [Select]
  1. [CommandMethod("Test_04")]
  2. public static void test04Command()
  3. {
  4.         Document doc = acadApp.DocumentManager.MdiActiveDocument;
  5.         Database db = doc.Database;
  6.         Editor ed = doc.Editor;
  7.  
  8.         DateTime TimeStart = DateTime.Now;
  9.  
  10.         string outputFileName = @"C:\Temp\EvalReport_04.txt";
  11.  
  12.         int attributeCount = 0;
  13.  
  14.         StreamWriter logFileWriter = null;
  15.  
  16.         try
  17.         {
  18.                 logFileWriter = new StreamWriter(outputFileName, true, System.Text.Encoding.ASCII);
  19.                 logFileWriter.AutoFlush = true;
  20.                 logFileWriter.WriteLine("Starting eval...");
  21.  
  22.                 ObjectId btId = db.BlockTableId;
  23.                 if (btId.IsNull || !btId.IsValid)
  24.                 {
  25.                         ed.WriteMessage("{0}Serious error: Failed to get BlockTable ObjectId!.", Environment.NewLine);
  26.                         return;
  27.                 }
  28.  
  29.                 BlockTable bt = btId.Open(OpenMode.ForRead, false) as BlockTable;
  30.                 if (bt == null)
  31.                 {
  32.                         ed.WriteMessage("{0}Catastrophic error: Failed to open the BlockTable!", Environment.NewLine);
  33.                         return;
  34.                 }
  35.  
  36.                 // roll over the block table
  37.                 foreach (ObjectId btrId in bt)
  38.                 {
  39.                         //BlockTableRecord btr = tr.GetObject(btrId, OpenMode.ForRead, false) as BlockTableRecord;
  40.                         BlockTableRecord btr = btrId.Open(OpenMode.ForRead, false) as BlockTableRecord;
  41.                         if (btr == null)
  42.                         {
  43.                                 ed.WriteMessage("{0}Serious error: Failed to open a BlockTableRecord! Continuing...", Environment.NewLine);
  44.                                 continue;
  45.                         }
  46.  
  47.                         if (!btr.HasAttributeDefinitions)
  48.                         {
  49.                                 btr.Close();
  50.                                 continue;
  51.                         }
  52.  
  53.                         ObjectIdCollection blkRefIds = btr.GetBlockReferenceIds(false, false);
  54.                         if (blkRefIds == null || blkRefIds.Count == 0)
  55.                                 continue;
  56.  
  57.                         foreach (ObjectId blkRefId in blkRefIds)
  58.                         {
  59.                                 //BlockReference blkRef = tr.GetObject(blkRefId, OpenMode.ForRead, false) as BlockReference;
  60.                                 BlockReference blkRef = blkRefId.Open(OpenMode.ForRead, false) as BlockReference;
  61.                                 if (blkRef == null)
  62.                                 {
  63.                                         ed.WriteMessage("{0}Serious error: Failed to open a BlockReference! Continuing...", Environment.NewLine);
  64.                                         continue;
  65.                                 }
  66.  
  67.                                 if (blkRef.Layer != "BLOCKS")
  68.                                 {
  69.                                         blkRef.Close();
  70.                                         continue;
  71.                                 }
  72.  
  73.                                 AttributeCollection attRefIds = blkRef.AttributeCollection;
  74.                                 if (attRefIds == null || attRefIds.Count == 0)
  75.                                 {
  76.                                         blkRef.Close();
  77.                                         continue;
  78.                                 }
  79.  
  80.                                 foreach (ObjectId attRefId in attRefIds)
  81.                                 {
  82.                                         //AttributeReference attRef = tr.GetObject(attRefId, OpenMode.ForRead, false) as AttributeReference;
  83.                                         AttributeReference attRef = attRefId.Open(OpenMode.ForRead, false) as AttributeReference;
  84.                                         if (attRef == null)
  85.                                         {
  86.                                                 ed.WriteMessage("{0}Serious error: Failed to open an AttributeReference! Continuing...", Environment.NewLine);
  87.                                                 continue;
  88.                                         }
  89.  
  90.                                         attributeCount++;
  91.  
  92.                                         logFileWriter.WriteLine(attributeCount.ToString() + '\t' + attRef.Tag + '\t' + attRef.TextString);
  93.  
  94.                                         attRef.Close();
  95.                                 }
  96.  
  97.                                 blkRef.Close();
  98.                         }
  99.                 }
  100.  
  101.                 //tr.Commit();
  102.                 bt.Close();
  103.  
  104.                 TimeSpan TimeDuration = (DateTime.Now - TimeStart); ;
  105.  
  106.                 ed.WriteMessage("End eval...Process time: "
  107.                                 + (TimeDuration.TotalSeconds + " Seconds for "
  108.                                 + attributeCount.ToString() + " records of "
  109.                                 + db.ApproxNumObjects.ToString()));
  110.  
  111.                 logFileWriter.WriteLine(("End eval...Process time: " + (TimeDuration.TotalSeconds + " Seconds.")));
  112.         }
  113.         catch (Autodesk.AutoCAD.Runtime.Exception arex)
  114.         {
  115.                 ed.WriteMessage("{0}AutoCAD Runtime Exception: {1}", Environment.NewLine, arex.Message);
  116.                 return;
  117.         }
  118.         catch (System.Exception ex)
  119.         {
  120.                 ed.WriteMessage("{0}System Runtime Exception: {1}", Environment.NewLine, ex.ToString());
  121.                 return;
  122.         }
  123.         finally
  124.         {
  125.                 if (logFileWriter != null)
  126.                         logFileWriter.Close();
  127.         }
  128.  
  129. }
  130.  

Cheers,
Glenn.


edit:kdub code=csharp
« Last Edit: August 16, 2012, 10:21:00 PM by Kerry »

Glenn R

  • Guest
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #17 on: March 16, 2008, 10:11:25 AM »
It's probably something simple that I'm overlooking...

Glenn R

  • Guest
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #18 on: March 16, 2008, 10:26:46 AM »
Interesting. I got it to work in AutoCAD 2006 and 2007 by SPECIFICALLY linking against those particular managed dll's for each product.

It is a bit faster, even more so when it's been jitted...I think you might find it get's down close to the ARX solution...which is how I would have done it btw.

Cheers,
Glenn.

Glenn R

  • Guest
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #19 on: March 16, 2008, 10:43:45 AM »
OK, I got it to work in 2008 as well, linking against the managed 2008 libraries.

The error being thrown was a null reference exception from ObjectId.GetObject() even though I wasn't using that. It appears that Object.Open in 2008 forwards a call to ObjectId.GetObject() which requires a top level transaction.

So, I added a transacton in, but still using ObjectId.Open() and voila.

Updated code for those masochists amongst us:

Code - C#: [Select]
  1. [CommandMethod("Test_04")]
  2. public static void test04Command()
  3. {
  4.         Document doc = acadApp.DocumentManager.MdiActiveDocument;
  5.         Database db = doc.Database;
  6.         Editor ed = doc.Editor;
  7.  
  8.         DateTime TimeStart = DateTime.Now;
  9.  
  10.         string outputFileName = @"C:\Temp\EvalReport_04.txt";
  11.  
  12.         int attributeCount = 0;
  13.  
  14.         Transaction tr = null;
  15.         StreamWriter logFileWriter = null;
  16.  
  17.         try
  18.         {
  19.                 logFileWriter = new StreamWriter(outputFileName, true, System.Text.Encoding.ASCII);
  20.                 logFileWriter.AutoFlush = true;
  21.                 logFileWriter.WriteLine("Starting eval...");
  22.  
  23.                 tr = db.TransactionManager.StartTransaction();
  24.  
  25.                 ObjectId btId = db.BlockTableId;
  26.                 if (btId.IsNull || !btId.IsValid)
  27.                 {
  28.                         ed.WriteMessage("{0}Serious error: Failed to get BlockTable ObjectId!.", Environment.NewLine);
  29.                         return;
  30.                 }
  31.  
  32.                 BlockTable bt = btId.Open(OpenMode.ForRead, false) as BlockTable;
  33.                 if (bt == null)
  34.                 {
  35.                         ed.WriteMessage("{0}Catastrophic error: Failed to open the BlockTable!", Environment.NewLine);
  36.                         return;
  37.                 }
  38.  
  39.                 // roll over the block table
  40.                 foreach (ObjectId btrId in bt)
  41.                 {
  42.                         //BlockTableRecord btr = tr.GetObject(btrId, OpenMode.ForRead, false) as BlockTableRecord;
  43.                         BlockTableRecord btr = btrId.Open(OpenMode.ForRead, false) as BlockTableRecord;
  44.                         if (btr == null)
  45.                         {
  46.                                 ed.WriteMessage("{0}Serious error: Failed to open a BlockTableRecord! Continuing...", Environment.NewLine);
  47.                                 continue;
  48.                         }
  49.  
  50.                         if (!btr.HasAttributeDefinitions)
  51.                         {
  52.                                 btr.Close();
  53.                                 continue;
  54.                         }
  55.  
  56.                         ObjectIdCollection blkRefIds = btr.GetBlockReferenceIds(false, false);
  57.                         if (blkRefIds == null || blkRefIds.Count == 0)
  58.                                 continue;
  59.  
  60.                         foreach (ObjectId blkRefId in blkRefIds)
  61.                         {
  62.                                 //BlockReference blkRef = tr.GetObject(blkRefId, OpenMode.ForRead, false) as BlockReference;
  63.                                 BlockReference blkRef = blkRefId.Open(OpenMode.ForRead, false) as BlockReference;
  64.                                 if (blkRef == null)
  65.                                 {
  66.                                         ed.WriteMessage("{0}Serious error: Failed to open a BlockReference! Continuing...", Environment.NewLine);
  67.                                         continue;
  68.                                 }
  69.  
  70.                                 if (blkRef.Layer != "BLOCKS")
  71.                                 {
  72.                                         blkRef.Close();
  73.                                         continue;
  74.                                 }
  75.  
  76.                                 AttributeCollection attRefIds = blkRef.AttributeCollection;
  77.                                 if (attRefIds == null || attRefIds.Count == 0)
  78.                                 {
  79.                                         blkRef.Close();
  80.                                         continue;
  81.                                 }
  82.  
  83.                                 foreach (ObjectId attRefId in attRefIds)
  84.                                 {
  85.                                         //AttributeReference attRef = tr.GetObject(attRefId, OpenMode.ForRead, false) as AttributeReference;
  86.                                         AttributeReference attRef = attRefId.Open(OpenMode.ForRead, false) as AttributeReference;
  87.                                         if (attRef == null)
  88.                                         {
  89.                                                 ed.WriteMessage("{0}Serious error: Failed to open an AttributeReference! Continuing...", Environment.NewLine);
  90.                                                 continue;
  91.                                         }
  92.  
  93.                                         attributeCount++;
  94.  
  95.                                         logFileWriter.WriteLine(attributeCount.ToString() + '\t' + attRef.Tag + '\t' + attRef.TextString);
  96.  
  97.                                         attRef.Close();
  98.                                 }
  99.  
  100.                                 blkRef.Close();
  101.                         }
  102.                 }
  103.  
  104.                 bt.Close();
  105.  
  106.                 tr.Commit();
  107.  
  108.                 TimeSpan TimeDuration = (DateTime.Now - TimeStart); ;
  109.  
  110.                 ed.WriteMessage("End eval...Process time: "
  111.                                 + (TimeDuration.TotalSeconds + " Seconds for "
  112.                                 + attributeCount.ToString() + " records of "
  113.                                 + db.ApproxNumObjects.ToString()));
  114.  
  115.                 logFileWriter.WriteLine(("End eval...Process time: " + (TimeDuration.TotalSeconds + " Seconds.")));
  116.         }
  117.         catch (Autodesk.AutoCAD.Runtime.Exception arex)
  118.         {
  119.                 ed.WriteMessage("{0}AutoCAD Runtime Exception: {1}", Environment.NewLine, arex.Message);
  120.                 return;
  121.         }
  122.         catch (System.Exception ex)
  123.         {
  124.                 ed.WriteMessage("{0}System Runtime Exception: {1}", Environment.NewLine, ex.ToString());
  125.                 return;
  126.         }
  127.         finally
  128.         {
  129.                 if (tr != null)
  130.                         tr.Dispose();
  131.                 if (logFileWriter != null)
  132.                         logFileWriter.Close();
  133.         }
  134.  
  135. }
  136.  

If you want to see the error I mentioned, just comment out all the transaction lines.

Cheers,
Glenn.


edit:kdub code=csharp
« Last Edit: August 16, 2012, 10:21:39 PM by Kerry »

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #20 on: March 16, 2008, 11:51:41 AM »
I guess they really want you to use the transaction manager :) This one ran a little slower
… End eval...Process time: 0.1301872 Seconds for 923 records of 109993 very strange.
It would be interesting to put these under a profiler to see where the actual bottleneck is.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #21 on: March 17, 2008, 11:23:31 AM »
I posted this once before,  but removed it after I noticed I screwed up.
I wonder if someone with a dual/quad core processor or multi-processor machine ,
.NET 3.5 and VS 2008(express is ok), that’s feeling brave might want to test this for me.  :wink:

You will need to install this
http://www.microsoft.com/downloads/details.aspx?FamilyID=e848dc1d-5be3-4941-8705-024bc7f180ba&displaylang=en

In theory, this code should run approximately the same speed on single cores and faster on multi cores. The commands are test1 and test2 that make files c:\EvalReport_01.txt and c:\EvalReport_02.txt,

I have attached the solution and dlls


Edit: Ps test it on a COPY of a BIG drawing with lots of blocks and attributes and stuff
« Last Edit: March 18, 2008, 02:49:51 AM by Daniel »

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #22 on: March 18, 2008, 05:08:01 AM »
Command: Test2
Process time: 0.03125 Seconds for 12103 Objects

except It doesn't add data to the file :-)

Test1
Command: Test1

 Thread ID15
Process time: 0.0625 Seconds for 12103 Objects

ditto .. no data in file   :|

but it is fast !   :-P

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #23 on: March 18, 2008, 05:20:28 AM »
Kerry ,

Thanks very much for trying this  8-)

Test1 should have been faster than Test2, but it’s good news that test1 did not throw an exception in reading the database from multiple threads

Maybe it didn’t write the file because I have changed the path to C:\ .. or because I changed the layer? It would be interesting to see test1's output to see how many thread were spawned. Anyway I really need to get myself a new computer  :lol:

Thanks again Kerry

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #24 on: March 18, 2008, 06:42:27 AM »
I'm an idgit !!

the word layer nudged me ..

Command: _laycur

Select objects to be changed to the current layer: Specify opposite corner:
6930 found

Select objects to be changed to the current layer:

6930 objects changed to layer "1_8_TEXT" (the current layer).
Command: netload

Command: test1

 Thread ID14
Process time: 0.484375 Seconds for 12107 Objects
Command: Test1
 Thread ID18
Process time: 0.203125 Seconds for 12107 Objects

Command: test2
Process time: 0.3125 Seconds for 12107 Objects
Command: Test2
Process time: 0.359375 Seconds for 12107 Objects
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #25 on: March 18, 2008, 06:58:43 AM »
Outstanding!! Thank you. It seems there is a little JIT time on the first run, which is OK. It wasn’t a doubling of speed, but I would say this is a pretty big increase
Did it generate an output file?

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #26 on: March 18, 2008, 08:32:11 AM »

Yes, generated one thread only.
both runs used #16.
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #27 on: March 18, 2008, 09:34:39 AM »
Hmm, Thanks,
I guess I need to study this more, What’s interesting is that the thread ID on your command line jumped from 14 to 18 where mine jumps by one thread at a time.
I wonder if the text writer spawned its own thread…

Now I have an excuse to go and purchase a new computer.  ;-)

Thanks again for your help

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #28 on: March 19, 2008, 05:09:35 AM »
<   >
So, I added a transacton in, but still using ObjectId.Open() and voila.

Updated code for those masochists amongst us:

Code: [Select]
[CommandMethod("Test_04")]
public static void test04Command()
{
//<>
}

If you want to see the error I mentioned, just comment out all the transaction lines.

Cheers,
Glenn.

nice looking code Glenn .. I'll have a better look over the weekend ; after I've finished the chocolate egg hunt  ;-)


btw:
chasing the last 1/10 of a second falls second to having maintainable and safe code ... but I think we've discussed this previously ...

« Last Edit: March 19, 2008, 05:12:55 AM by Kerry Brown »
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Glenn R

  • Guest
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #29 on: March 19, 2008, 05:15:32 AM »
Thanks Kerry.

Yes we have discussed the speeeeed vs. purdiness issues before and I agree with you.

Cheers,
Glenn.