Notifications
Clear all

[Closed] Maxscript challenge ideas

 lo1

It seems that all our versions so far are WRONG.


(
	print "V1"
	start = timestamp()
	seed(timestamp())
	mem = heapfree
	results = for i = 1 to 10000 collect i
	for i = 1 to 10000 do swap results[i] (results[random 1 10000])
	end = timestamp()
	format "processing: % seconds heap: %
" ((end - start) / 1000.0) (mem-heapfree)
	results = makeUniqueArray results
	format "There are % duplicate results
" (10000-results.count)
)

processing: 0.012 seconds heap: 560240L
There are 5046 duplicate results
 lo1
(
	start = timestamp()
	seed(timestamp())
	mem = heapfree
	results = for i = 1 to 10000 collect i
	for i = 1 to 10000 do 
	(
		swap results[i] results[random 1 10000]
	)
	end = timestamp()
	format "processing: % seconds heap: %
" ((end - start) / 1000.0) (mem-heapfree)
	results = makeUniqueArray results
	format "There are % duplicate results
" (10000-results.count)
)

(
	start = timestamp()
	seed(timestamp())
	mem = heapfree
	results = for i = 1 to 10000 collect i
	for i = 1 to 10000 do 
	(
		local ind = random 1 10000
		swap results[i] results[ind]
	)
	end = timestamp()
	format "processing: % seconds heap: %
" ((end - start) / 1000.0) (mem-heapfree)
	results = makeUniqueArray results
	format "There are % duplicate results
" (10000-results.count)
)


processing: 0.012 seconds heap: 560240L
There are 4976 duplicate results
OK
processing: 0.015 seconds heap: 560264L
There are 0 duplicate results
OK

seems there is some problem with swap method. The first block of code does not work, while the second one does. Anyone have any ideas why this happens?

No ideia why it happens, but I’ve corrected my V5 version to use a local var for the index.

Btw… how about splitting the randomization in two threads? he he he check it out.

This is the V5 corrected:

(
	print "V5"
	gc()
	start = timestamp()
	seed(timestamp())
	mem = heapfree
	asize = 1000000
	results = for i = 1 to asize collect i
	for i = 1 to asize do 
	(
		idx = random i asize
		swap results[i] results[idx]
	)
	end = timestamp()
	format "processing: % seconds heap: %
" ((end - start) / 1000.0) (mem-heapfree)
)
(
	print "V6"
	gc()
	startg = timestamp()
	seed(timestamp())
	mem = heapfree
	asize = 1000000
	results = for i = 1 to asize collect i
		
	fn dowork1 =
	(
		start = timestamp()		
		for i = 1 to results.count/2 do 
		(
			idx = random i asize
			swap results[i] results[idx]
		)
		end = timestamp()
		format "processing: % seconds heap: %
" ((end - start) / 1000.0) (mem-heapfree)		
	)
	
	fn dowork2 =
	(		
		start = timestamp()		
		for i = (results.count/2)+1 to asize do
		(
			idx = random i asize
			swap results[i] results[idx]
		)
		end = timestamp()
		format "processing: % seconds heap: %
" ((end - start) / 1000.0) (mem-heapfree)		
	)
	
	MainThread = dotnetobject "System.ComponentModel.BackGroundWorker"
	
	print "MainThread"	
	dotNet.addEventHandler MainThread "DoWork" dowork1
	--------------------
	SecondaryThread = dotnetobject "System.ComponentModel.BackGroundWorker"
	
	print "SecondaryThread"
	dotNet.addEventHandler SecondaryThread  "DoWork" dowork2
	-----------------------
	MainThread.RunWorkerAsync()
	SecondaryThread.RunWorkerAsync()
	
	
	endg = timestamp()
	format "processing: % seconds heap: %
" ((endg - startg) / 1000.0) (mem-heapfree)
)

The results:

"V5"
processing: 1.428 seconds heap: 56074760L
OK
"V6"
"MainThread"
"SecondaryThread"
processing: 0.378 seconds heap: 56076304L
OK
processing: 0.591 seconds heap: 56076512L
processing: 0.592 seconds heap: 56076576L

Since the V6 is multithreaded I assume we have to sum the first processing, which is the global script execution with the highest of the two next processings times to have an accurate result, so in this case it would be something like 0.378 + 0.592 = 0.97

He he under 1 second

4 Replies
(@denist)
Joined: 11 months ago

Posts: 0

good idea! but the method needs correction. it generates duplicates…

 lo1
(@lo1)
Joined: 11 months ago

Posts: 0

Using the local var seems to be fine…

(@kameleon)
Joined: 11 months ago

Posts: 0

It does? but each thread is working on half the array… and my random is using i to 1000000 and not 1 to 1000000, so it should be ok, but I havent tested for duplicates with makeUniqueArray.

(@denist)
Joined: 11 months ago

Posts: 0

makeUniqueArray is very slow. use (<array> as bitarray).numberset

I’ve got another trick up my sleeve… hang on

Well, you can add more and more threads as long as you have them I just used two for showing purposes Bring it on!

You can do multi-threaded like that!? Would this work on other intensive maxscripts, like getting alot of object positions or vert positions and whatnot?

Like break up a mesh into 2 vert sets, and send both off 2 Two CPUs and get them back?

Very cool stuff so far

Yeah, for sure, just check out a blog post by lonerobot where he gives a small intro and example for working with this class. The only thing I dont think you can do directly in maxscript is to get how many threads the cpu has, but you can write a custom dll for that or just use that runtime compiling that denisT does alot. That way, you could in theory get how many threads the cpu has, divide your array by that and assign that to each thread. Never tried it before except today with this example.

edit: forget all the above, here you go: sysinfo.cpucount (I’ve used it in iray Manager)

Awesome! yeah, I was going to say, I thought I saw a cpu count somewhere. I will have to look at this tonight/this weekend for sure

I wonder why Autodesk doesn’t have maxscripts run on all cores by default…?

It doesn’t work for scene object manipulation as far as I know.


     gc()
   ts = timestamp()
    mem = heapfree
   
    p=0
    n=1000000
    
    fn compareFN v1 v2=
   ( 
   	ind=(random 2 n)
      
   	tmp=results[1]   --always swap with index 1, doesnt matter, we have no index pointer here.
   	results[1]= results[ind]
   	results[ind]=tmp
   	--p=p+1
   	 1  -- return 1 for the qsort function
   )
   
   results = for i = 1 to n collect i  -- just generate a filler array
    
   dmy=#()
   dmy[2000]=0 -- sorting an array with count=2000 results in 1002004 itterations of the shuffle loop, array empty so almost no memory use.
   
   qsort dmy  compareFN   -- abuse the qsort function to just internally swap the array values
    
   --print results  -- uncomment en set n=10 to see if the algorithm works
   
   format "Time: %, Memory: %
" (timestamp()-ts) (mem-heapfree)
   
   --print p   --uncomment this and the p=p+1 in the function to see the number of shuffles
   
   
   

On my machine this is twice as fast as Lo’s winning solution (3.8 vs 7.9 sec) so if someone can confirm that it would be nice

It’s a bit of a weird method, I let qsort call it’s sort function. That function doesn’t sort but it shuffles the array and always returns a ‘1’.

Sorting an empty dummy array that is 2000 entries long results in 1002004 calls to the function. which is just over the number of iterations that is needed to shuffle or source array.

I suspect that qsort is calling the function in a more efficient way that doing it in a higher level loop.

edit: added a gc() to the script… seems to make it go even faster… 2.7s on my machine (8 core xeon, 5420 2.something GHz… so not really fast per single core )

Page 5 / 12