Steven Caron, OBJ Files, Sexy Bits and Waste
March 1st, 2008 by Patrick Boucher - Viewed 25232 times -What do all these things have in common?
The weird wirings in my brain. That’s what.
Back to the beginning
At the end of last October Steven Caron sent me a plugin he wrote that allows an XSI user to drag and drop .obj files into the interface and have them import automatically according to settings in a custom preference. I was a bit swamped at the time putting up the infrastructure for a new VFX department at my new workplace. And then I totally forgot about it… Sorry Steven.
This past week Steven politely reminded me of my omission so I ran back to my email archives and installed it. Neat piece of work.
I didn’t want to just post up the tool as I don’t really see this blog being about tool distribution but about how said tools work and the neat tricks they use. With that philosophy in mind I cracked open Steven’s tool to dig out some of its sexier bits and maybe demystify them for the audience.
To my surprise there weren’t any sexy bits. Please don’t get me wrong, the tool works superbly, how much more intuitive can you get than drag and drop. The tool is also extremely well written, concise and straightforward. There just aren’t any weird tricks or convoluted syntax or things that would generally have you scratching your head.
Then I noticed this in his version trapping code (yes folks, the drag and drop event is new in XSI 6.5):
27 28 29 30 31 32 33 34 35 | if int( tXSIVersion[0] ) < 6: xsiPrint( xsi.Version() + " doesn't support the 'siOnDragAndDrop' event!" ) xsi.UnloadPlugin( in_reg.name, True ) return False else: if int( tXSIVersion[1] ) < 5: xsiPrint( xsi.Version() + " doesn't support the 'siOnDragAndDrop' event!" ) xsi.UnloadPlugin( in_reg.name, True ) return False |
About the waste part
Bare with me…
Last week I was reading a really neat article in Wired by Chris Anderson entitled “Free! Why $0.00 Is the Future of Business”. I invite you to read it, especially the section beginning on page two: Waste and Waste Again.
…So if in the seventies you had to be really tight with your algorithms and optimizations because cpu cycles were so scarce, today I guess we can really waste them. Just the other day I setup an 8 core MacPro with BootCamp, XP x64 and XSI. Whatever I did to the machine, I swear, I could hear it yawn because it was bored.
Which brings me back to Steven’s code. Could it have been written like so:
27 28 29 30 | if int( tXSIVersion[0] ) < 6 or int( tXSIVersion[1] ) < 5: xsiPrint( xsi.Version() + " doesn't support the 'siOnDragAndDrop' event!" ) xsi.UnloadPlugin( in_reg.name, True ) return False |
Is it more or less readable by a programmer?
It probably executes in a few cycles less but is it worth it?
Python is interpreted so if the parser goes through this version quicker, is it worty of any mention?
Is it more maintainable?
This example is really simple but in a bigger project, or with more complex cases, should we really be worrying if today transistors and cpu cycles are so cheap as to not even matter anymore
When I'm stuck on a piece of code or when I hit that time of the afternoon where most of my energy is diverted to digesting, I'll often reread my code and tighten it, remove redundancy, put in functions instead of copying a few lines in two locations, consolidate if statements, etc... One of my colleagues used to tell me that "Premature optimization is the root of all evil."
Honestly, if I look back at a good proportion of the code I have written, it either executes in a blink of an eye on today's computers or it sits there waiting 90% of the time for user interaction. Should we, as technical XSI users, XSI scripters or TDs, even worry about optimization from a performance standpoint or a maintainability standpoint? What can be considered a good optimization and what should be considered a bad one?
And now that you're really wondering what I'm rambling about, I'll shut up and let you download Steven's addon.
Have a good weekend.
thanks for posting this patrick! i appreciate the peer review of my code also, i dont get that luxury with my personal projects.
Yay! The blog is back :-)
Actually, I hate to be the one to point it out, but both code segments will fail for any version that has a minor version less then 5. That includes 7.0, 7.1, etc. Whoops!
I’d probably test for it like this:
if int( tXSIVersion[0] )
Gah. The html didn’t like the less than sign.
It should have looked like this..
To address the main point of the article, I think the revised form is definitely a better style. When I read the first code snippet, I had to read it again to see if there was a difference between the bodies of the two ‘if’ statements, which of course there isn’t. So for me, it’s more about readability than anything.
I wouldn’t even put it into the category of premature optimisation. The following I would consider to be premature optimisation, and it’s not something I’d code on a first pass, but would introduce during factorising. It improves readability, plus it avoids a list lookup, albeit at the cost of having two temporary variables in memory.
For me, whether TDs take time to optimise and factorise their code or not depends on what the code is for. If it’s just a quick script to batch process something, then no, it’s probably not worth it. If it’s a SCOP, then yes, performance is everything.
More crucially, if a TD is writing code for a pipeline, then clarity is incredibly important. TDs come and go, yet their code often remains. If it hasn’t been left in a maintainable state then it can lead to misunderstandings and new bugs. Worse still, a new recruit may decide to rewrite it, because it’s less effort than trying to understand what it does.
That’s why, for me, I think readability is key. If something needs to be optimised to the point where the code does not express it’s purpose, then comments are essential to instruct a newcomer as to what is happening.
Andy:
Touché on comment #2.
And you bring up nice points on comment #3. I can only beg for forgiveness when I think of the person that might today be playing around in code I’ve left behind… ;)
Hehe. Yep, we’re all guilty of that :-)
i have made a jscript version for the non python adopters…
http://www.steven-caron.com/downloads/tools/objDnD_js.xsiaddon
i have the plugins hosted at my site, but patrick is welcome to host them here too.
I consider performance/optimization and maintainability to be two very distinct aspects of programming.
I approach performance/optimization mainly from a business perspective. Since it’s the user that’s going to run my script, the experience for the user has to be as pleasant as possible. As far as speed is concerned, that means as fast as possible. Any excuse is good for someone to go out for another cigarette, if you see what I mean (in my case, it’s surfing the internet for a much longer time than the actual execution, as I won’t stop reading in the middle of a paragraph or in the middle of writing a post on a forum). In a sentence, the longer an artist waits, the more expensive it is for the studio. There are already countless other reasons to wait, do not make matter worse if you can avoid it! I think any reasonable step a coder can take to reduce the execution to a minimum is good. There is no point in wasting cpu cycles just because we can!
In my case I’m hardly ever too premature. Very often my code will go through many changes just to better organize it, and sometimes these changes will take me several hours (or even several days) to implement. Sometimes I realize I wrote a function that is called only once, so I put it in the main code, sometimes I realize that I have a wacky combination of if/else, so I change it to a dictionary look (sort of like a switch), etc. It is something that is done at all stages of the development, not just at the end. I optimize as I see fit.
As for maintainability, I agree with Andy. I don’t see optimization and maintainability being incompatible. I go to great lengths to comment my code. Most functions and classes have a doc string, with arguments and return value described. I write the doc strings at the end of the development, because functions are subject to many changes. Annoying to re-write the doc string every time. Above lines that seem to do weird things, I put multiline comments.
In the case of highly sensitive code, like pipeline framework, I might even write a proper documentation, detailing each class, method, attribute, as well as a walk-through of the architecture. Of course this has to be done late in the development, for the same reason as doc strings. Maintaining documentation can be a lot of work. Again this documentation is not just for others, but to me as well.
In the case of the example above, I’d write it this way:
So all functions all called only once. Only one comparison operation.
Ok, first off I think we’ll all agree I’m being extremely stupid testing this but I had to.
I was seriously having my doubts as to the speed of Bernard’s approach, and if it wasn’t quicker, IMHO, Andy’s code is much more readable. My doubts lied in three things:
- The join just doesn’t exist in the other versions.
- I figure a float conversion must be slower than an int conversion – gotta check for that period.
- And lastly the round that doesn’t exits in the other versions.
I included Steven’s version as well as mine in the tests even if we all agree that they don’t even work for letting through a ’7.0′ version string incorrectly.
Here are the results I got for 10000000 iterations of our code bits. Yeah, ten million, that’s the stupid part of all this!
The andyNoTempVar is Andy’s code without the two temporary variables. Duh. And as it turns out, it is the clear winner.
This is what I used to test. If anyone finds problems with this, please point them out.
Yes, I’m timing a range loop, a function call and variable passing but they are the same in all tests so they kind of cancel out. The time differences we notice are due to the contents of the various functions.
Nice! Thanks a lot for this!
Oops.
The andyNoTempVar function should have read:
I’d forgotten the explicit int conversions. It winds up being slower than the temp variable version in function andy. So, the temp var version, for having one less conversion creeps ahead in the standings of two tests. New numbers, again with ten million runs:
I have to say that I like Bernards method for the elegance of the procedure. I think it is a little harder to read and understand at first glance, but that’s why he’s been good enough to put nice big comments there :-D
Thanks for doing the testing Patrick.
sweet… i was feeling all dumb about my if/else if setup and it runs with acceptable speed.
i do find bernard’s harder to read and i dont think i would opt for his code because code maintenance is often shared (your comments go a long way and make up for it) between developers and when i leave the code for a few months and come back i dont want to be scratching my head because i didn’t comment :)
fun stuff! true purpose of xsiblog!
s
Hey guys, check this out.
I thought that all we were interested in is the version to be 6.5 or more. That’s it. The number of digits after the decimal doesn’t matter.
So I thought that I could simply take the 3 first characters, convert them to float, and test against that. If the XSI version is ever going to be above 9, it doesn’t matter, because at 10 we know for sure we’re beyond 6.5.
So wrote this function. No split, no join, no round, no conversion to int, only one comparison.
(let me know if I’ve overlooked something!)
And then I ran Patrick’s test code (although I only did 1,000,000 iterations, as my computer is slower than his). My results:
You’ll also notice this entry: bernardList. I wanted to see how things go if I converted the number to integers via a list comprehension:
I love this stuff!
Bernard
Me again,
I reworked the function a little bit. In bernardFloat(), I change the not … >= to a simple <.
I also added bernardFloat2(), which does the same thing except creating a temp variable.
New results:
So skipping the temp variable is even faster!
Thanks, folks!
As a novice scripter, I found this all to be very informative.
Stumbled onto this article describing Python optimization this morning.
Thought it was appropriate.
http://www.python.org/doc/essays/list2str.html
Very interesting link that (for nerds like me anyway). Thanks :-)
ok so this is definitely a Softimage Bad Ass comments section. I stopped listening at ‘Python if int blah’ unfortunately, but maybe give me another 4 years? ran Ciaran’s python prt2icecache.py from a Naiad export today so am allowed to comment? :)