Notifications
Clear all

[Closed] A Benchmarking Study

It’s my way, because it’s how I do it’,
but it’s the obvious way to use nodeTM with full control iinstead of the hardcoded version inside mxs_cotronllers, :


(
	delete objects
	clearlistener()
	local node, parent
	

	count = 5
	global nodes = for k=0 to count-1 collect in parent 
	(
		node = box name:("B" + k as string) width:10 length:10 height:10 pos:[k*15,0,-5] wirecolor:(color 0 (250-k*10) (250-k*10))
			
		if isvalidnode parent do
		(
			sc = node.pos.controller[1].controller = float_script()
			cat = attributes weak (parameters main(ref type:#maxobject subAnim:true))
			custAttributes.add sc cat
			
			sc.ref = NodeTransformMonitor node:parent forwardTransformChangeMsgs:false
			
			sc.addconstant "id" k
-- 			sc.addnode "parent" parent
			sc.addObject"parent" sc.weak
-- 			sc.setexpression ("print (\"id: \" + (id as string)); parent.pos.controller[1].value; " + sc.script)
			sc.setexpression ("print (\"id: \" + (id as string)); parent.ref.node.pos.controller[1].value; " + sc.script)
		)	
		parent = node
		node
	)
	format ">>>>>>
"	
	move nodes[1] [0,0,0]
)

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

you method unfortunately doesn’t work. change expression with:


sc.setexpression ("print (\"id: \" + (id as string)); parent.ref.node.pos.controller[1].value + 15")

and you will see that expression doesn’t evaluate on any root node (B0) move

max 2012/64


script		>>	time:75	memory:3726664L
param wire	>>	time:27	memory:120L
expression	>>	time:8	memory:120L
constraint	>>	time:9	memory:518176L
expose tm	>>	time:11	memory:1282312L

i worry about constrains… all script controllers in my rig i changed with expression controllers. but what can i do with constraints? they are main solution for any rig.

i found that my rig leaks with memory in 2012… and honestly i don’t have any idea how to fix it.

denisT, that’s how an unidirectional nodeTM is supposed to be.
And that’s exactly what we want.

off topic I’d like in max, CONTROL of every message, but that’s not possible without a nodal system and a complete rewrite of the reference system.

we have weak references to choose…

do you want parent to update children,
do you want children to update parent,

that’s bidirectionality…

you want full efficiency, control every message,
that’s something I’ve fancied long before ICE in softimage…
but it’s not supported by max archaic core.

the way addNode works, is logical, simple, (not the best way), but I would not call it a leak.

now many times we just want to GET a value.
but people do things that creates extra messages they don’t really need.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

the leakage is different story. it’s not related to the node transform monitoring.
empty scripted controller leaks the same badly:


(
	b1 = box()

	b2 = box()
	b2.pos.controller = position_script()

	gc()
	t1 = timestamp()
	m1 = heapfree
	for k=1 to 10000 do b1.pos
	format "origin		>>	time:%	memory:%
" (timestamp() - t1) (m1 - heapfree)

	gc()
	t1 = timestamp()
	m1 = heapfree
	for k=1 to 10000 do b2.pos
	format "script		>>	time:%	memory:%
" (timestamp() - t1) (m1 - heapfree)
)

i want that slave controller doesn’t evaluate master controller. i can stop forward transform messages (as you do) but in this case i have to notify all dependents myself.

maybe,
I’s a matter of testing I guess.

The thing is, people who posts about weak references don’t know there are 2 kinds,
many don’t even know that mxs_controllers uses nodeTM
other don’t even know about indirect references to MAXObjects directly.


About the leaking, I was assuming the extra messages leaking…
memory, yes it’s a subject apart.

In the spirit of trying new things, I’ve been trying to replace several script controllers in my mxs tools with expression controllers. There are some definite performance improvements to be had. However I’ve run into some odd circular dependency errors.

For example. Lets say you have two custom attributes on a dummy object, one of which you assign an expression controller, the other is a linear float. You can add a scalar variable to the expression controller that points to one of the dummy’s own parameters, i.e. it’s own x position, put You seemingly cannot point to the other custom attribute, even if its just set as a constant?

Am i missing something silly here?


  miscAttribs = attributes "misc" 
  (
  	parameters blah
  	(
  		value1 type:#float
  		value2 type:#float
  	)
  )
  
  s1 = sphere radius:100 pos:[100,100,100]
  CustAttributes.add s1 miscAttribs #Unique baseObject:true
  s1.value1.controller = linear_float()
  s1.value1 = 666.6
  s1.value2.controller = float_expression()
  s1.value2.controller.addScalarTarget "posX" s1.position.controller[1]
  s1.value2.controller.setexpression "posX"
  
  s2 = sphere radius:100 pos:[300,300,300]
  CustAttributes.add s2 miscAttribs #Unique baseObject:true
  s2.value1.controller = linear_float()
  s2.value1 = 666.6
  s2.value2.controller = float_expression()
  s2.value2.controller.addScalarTarget "v1" s2.value1.controller -- this fails
  s2.value2.controller.setexpression "v1"
  
 PEN

Gota love all this. I don’t know why after all these years of me bitching to ADSK about controller issues this discussion is still going on. The whole way that max handles controllers and dependencies needs an over haul. I have been telling them this since Max 4 I think. Every version of Max my rigs get slower and slower and I’m able to do less and less with them. Recently I created a bone based facial rig that had to be scraped because of how slow it got an it had about half the dependencies that previous facial rigs had.

Great thread, I will see if I can find the time to contribute.

Hey all

We were discussing this last year and it seems that the methods that TDs thought were the right way to add functionality to rigs are just horrible now. I was chatting to a fellow TD (Michael Greenwood at Nexus). He always sets up rigs with a non-scripted approach (just parameter wiring and constraints) and he hadnt noticed such a bad performance hit. Judging on the results of these benchmarks you can see why.

On a slow rig, you notice when you can almost see the gears grinding when you select a root key in the curve editor and you feel like max is calculating everything else in the rig. But the trick now is to try to get the cool features that animators love without any cost. I have been re-thinking my rigging strategy for some time now, and am working on the idea that you can build node relationships with appdata rather than weak references and trying not to use scripted controllers.

It means that what rigs need is a diet rather than giving them with every feature you can think of. In the end a good animator will not complain if he doesn’t have an all-singing dancing curved spine rig, but hand over a slow rig and you’ll soon have people waiting for you at your desk with pitchforks.

I can swear that my rigs designed for max 6-7 worked 8 years ago much faster than today on max 2012.
Another big problem for me is memory leaking. The rig might not leak on max 2010 but it very badly leaks on max 2012. The worst situation is when I use Nitrous as veiwport driver.
Nitrous is continuously doing refining of view image and every time fires viewport redraw event.
It seams like some max controllers do update on view port redraw. At least they receive this message and decide what to do.

considering that:

# I moved everywhere where it's possible from script controller solution to something else (expression, constraint, wire).  
# I stopped using Reactor controllers
# I use NodeMonitor instead of NodeTransformMonitor or Node if I don't need transform messages
# I use maxobject type parameters in CA instead of adding node targets to scripted controller. 
...
gc()
t1 = timestamp()
m1 = heapfree
for k=1 to count do b3.rotation
format "param wire	>>	time:%	memory:%

” (timestamp() – t1) (m1 – heapfree)

Maxscript is a garbage collected system. The number you are showing is just the amount of mxs heap memory currrently being used. When mxs starts up, it allocates a block of memory to use as its heap. As mxs values are created, the heap memory usage goes up until mxs has used up all of its heap memory. Then mxs does a garbage collection, and the heap memory used goes way down. Repeat, lather, and rinse.

As you run max, if you periodically evaluate ‘heapfree’, the value you get will be constantly changing. Sometimes it will be high, sometimes low. It all depends on how long it has been (in terms of mxs value creation) since the last garbage collection.

Some of the controllers you show values for aren’t maxscript-based (constraint, expression, etc.) so their evaluations aren’t creating new mxs values, thus no change in max heap usage.

Larry

Page 2 / 2