Frequently Asked Questions > Writing Better and Faster Scripts > How To Make It Faster? >

# Disable Undo system when possible

MAXScript FAQ > How To Make It Faster > Disable Undo system when possible

The undo system can consume large amounts of memory and slow down processing.

- MAXScript commands run from Listener. Script Editor or Macro Script are run within an undo on context.

- MAXScript commands run from scripted UI controls are not run within an undo on context.

- Do not delete nodes with undo off, unless you also created the nodes with undo off and did not do anything to the node with undo on.

- When working with meshes, you typically want to use meshop methods as they support undo/redo. But typically you do not want to store undo records for all operations in a loop, just the first and last.

- When working with EPoly, you want to store undo records for all operations in a loop.

TEST CASE:
    em = mesh()
    meshop_setvert = meshop.setvert
    fn test7 holdAll =
    (
     local nVerts = getnumverts em
     for i = 1 to nVerts do
      with undo (holdAll or (i == 1 or i == nVerts))
       meshop_setvert em i ([1,1,1]*i)
    )

FOR 100,000 ITERATIONS:
    test7 true -- 85313 msec., 229 MB
    test7 false-- 7609 msec., 11 MB

Every operation that creates an undo record will cost time and memory as it will create internal copies of the changing objects to allow an undo later. When making multiple changes in a loop like for example attaching multiple objects together, the Undo system would attempt to create a single undo copy of each resulting object and might even run out of memory. Disabling Undo explicitly using the Undo off () context can help to speed up scripts significantly in such cases.

undo

The following extreme example shows the difference. In both cases, 1000 boxes will be created using MAXScript and then attached to a single mesh using the attach function. In the first case, each attach call will generate by default an undo record. In the second case, the undo will be explicitly disabled.

EXAMPLE 1 - UNOPTIMIZED SCRIPT:
    delete $Box*--delete any existing boxes
    box_array = #()--initialize an array
    for i = 1 to 1000 do--repeat 1000 times
      box_array[i] = box pos:[i*30,0,0]--create 1000 boxes
    st = timestamp()--get the start time in milliseconds
    master_box = convertToMesh box_array[1]--collapse the first box to mesh
    for i = 2 to 1000 do--go through all other boxes
      attach master_box box_array[i]--attach each box to the mesh
    et = timestamp()--stop the time
    print (et-st)--print the resulting time
    gc()--call Garbage Collection &endash; you will needed it!
On a 800MHz PC, the execution of the attaching part of the script took more than a minute mainly because the system run out of memory and the OS had to swap to disk. Memory usage for 3ds Max went up with about 300 MB!

EXAMPLE 2 - OPTIMIZED SCRIPT:
    delete $Box*
    box_array = #()
    for i = 1 to 1000 do
    box_array[i] = box pos:[i*30,0,0]
    st = timestamp()
    undo off--the only difference - the undo (--has been turned off
      master_box = convertToMesh box_array[1]
    for i = 2 to 1000 do
      attach master_box box_array[i]
    )--end undo off
    et = timestamp()
    print (et-st)
    --call Garbage Collection - you will needed it!
On the same 800MHz machine, the execution of the attaching part of the script took only 3685 milliseconds, almost 20 times faster! There were no memory consumption changes visible in the Windows Task Manager.

Previous Tip

Disable Viewport Redraws when making changes to scene objects

Next Tip

Modify Panel can be slow -change to Create Panel when possible