Revit2011 Transaction Performance

by Guy Robinson 17. April 2010 16:35

API performance has always been of interest, even more so as large projects regularly hit >300Mb now. With the new API’s such as updaters and the DocumentChanged event performance testing has got a lot more complicated. Throw in transaction and regeneration issues and it soon became obvious a different approach was required. I’m not ready to talk about this approach but I thought a little test on transactions speaks volumes about some of the additional design decisions API authors need now consider.

The test comprises 3 commands. One doing a single loop with a single transaction. The second uses a subtransaction per loop. The third one full transaction per loop. each command was run 10 times to average out variation per run. Here’s the results:

 

Run Single Transaction (ms) SubTransaction (ms) Full Transaction (ms)
1 795 1544 73085
2 852 1553 72935
3 778 1556 72797
4 784 1554 73170
5 781 1536 73837
6 789 1564 72334
7 787 1533 71912
8 778 1541 71782
9 793 1550 73472
10 777 1524 73290
Average 791.4 1545.5 72861.4

 

So as you can see subtransactions were twice as slow , this is an excellent result considering 10000 were committed against only one. However as expected the majority of the overhead in the single transaction test was the committing of the single transaction, as can be seen by the Full transaction test being ~9000% slower for 10000 transactions.

So in conclusion I feel we can say:

“Utilise subtransactions as required without fear of serious performance degradation. Be very careful when considering multiple transactions within a single command cycle.”

Update: Arnošt who is part of the API team at Autodesk left a thorough comment below. So I've added his conclusion here:

Do not use neither sub-transactions nor transactions unless you need them, but use them when the end-user benefits from having them..” 

And here’s the code:

Single Transaction:

try
{
    var doc = commandData.Application.ActiveUIDocument.Document;
    const int LOOPS = 10000;
    Stopwatch sw = Stopwatch.StartNew();
    var trans = new Transaction(doc, "transtest");
    trans.Start();
    for (int i = 0; i < LOOPS; i++)
    {
        doc.ProjectInformation.Name = "transtest" + i;
    }
    trans.Commit();
    sw.Stop();
    message = string.Format("Elapsed time for {0}== {1}", LOOPS, sw.ElapsedMilliseconds);
    return Result.Failed;
}
catch (Exception ex)
{
    message = ex.Message + ex.StackTrace;
    return Result.Failed;
}

Subtransaction:

try
{
    var doc = commandData.Application.ActiveUIDocument.Document;
    const int LOOPS = 10000;
    Stopwatch sw = Stopwatch.StartNew();
    var trans = new Transaction(doc, "transtest");
    trans.Start();
    for (int i = 0; i < LOOPS; i++)
    {
        var subTrans = new SubTransaction(doc);
        subTrans.Start();
        doc.ProjectInformation.Name = "transtest" + i;
        subTrans.Commit();
    }
    trans.Commit();
    sw.Stop();
    message = string.Format("Elapsed time for {0}== {1}", LOOPS, sw.ElapsedMilliseconds);
    return Result.Failed;
}
catch (Exception ex)
{
    message = ex.Message + ex.StackTrace;
    return Result.Failed;
}

Full Transaction:

try
{
    var doc = commandData.Application.ActiveUIDocument.Document;
    const int LOOPS = 10000;
    Stopwatch sw = Stopwatch.StartNew();
    
    for (int i = 0; i < LOOPS; i++)
    {
        var trans = new Transaction(doc, "transtest");
        trans.Start();
        doc.ProjectInformation.Name = "transtest" + i;
        trans.Commit();
    }
    
    sw.Stop();
    message = string.Format("Elapsed time for {0}== {1}", LOOPS, sw.ElapsedMilliseconds);
    return Result.Failed;
}
catch (Exception ex)
{
    message = ex.Message + ex.StackTrace;
    return Result.Failed;
}

Cheers,

Guy

Comments (2) -

Arnošt L&#246;bel
Arnošt Löbel United States
4/21/2010 7:16:42 AM #

I would probably phase it slightly differently than Guy in his main conclusion above (bold). My recommendation would be: “Do not use neither sub-transactions nor transactions unless you need them, but use them when the end-user benefits from having them.” The main purpose to utilize a sub-transaction in one’s code is to maintain the ability to reverse a series of actions (programming steps) in case something goes in way other than expected. If you do not need such ability in your code then you do not need sub-transactions, because it does not give you any additional benefit, for sub-transactions are not visible to end-users anyway. The purpose of transactions is to be able to change the model and show the changes (their description) to the end-user, who then has the option to undo and redo the changes if she pleases. Keep in mind that it would be rather inconvenient for the user to see hundreds or even just tens of changes especially if all of them have the same description. (Which one was for what?) Plus, Revit starts purging older transactions at some point, thus the user will never see 1000 transactions in the undo menu anyway. Transactions should be used as logical building blocks of changes – blocks should somehow make sense to the end user and it should also make sense (and be possible without compromising the integrity of the model) to undo them individually.

Arnošt Löbel

Guy Robinson
Guy Robinson
4/21/2010 7:28:31 AM #

Hi Arnošt,

Thank you for the very valid comments. Have updated the post.

Comments are closed

About the Author

A .NET software Developer providing custom applications and commands for architecture firms exclusively working with Autodesk Revit and integration with any associated applications. All from a little place north of Whitianga, New Zealand.

Page List

Disclaimer

I'm self employed so the opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway☺

© Copyright2008

Creative Commons License
Blog content is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

With the following exception. All code snippets, application and libraries are licensed under a a Apache License Version 2.0

Autodesk Revit®

Autodesk: Revit is a product that is wholly owned by Autodesk. Any reference to Revit,Revit API, Revit Architecture, Revit MEP or Revit Structure on this site is made acknowledging this ownership. Refer to Autodesk's own web site and product pages for specific trademark and copyright information. Autodesk represents a great many products and every attempt will be made to respect their ownership whenever one of these other products is mentioned on this site.