Note: Onshape update 1.180 improved performance of the normalize function.
Inspired by a discussion with fellow FeatureScript expert Jacob, and some recent customer requests, I've been surrounded by the topic of FeatureScript optimization. I wanted to give a short primer on optimizing FeatureScript, and some tips and tricks.
Regen time
The first thing to know about FeatureScript (and Onshape) is to know what we are looking to optimize. In a parametric CAD model, changing a feature's definition will cause the geometry of the model to update. If a feature in the middle of the tree is updated, all downstream features also need to update. The longer this regeneration takes, the slower updating and iterating a design will be. For most Onshape built in features, the performance is pretty good. But for extremely complex custom Features, that regen time can shoot up to huge numbers in the range of 1-20 minutes. I'm sure you can imagine how annoying it would be to update a model with a 20 minute regeneration time. Which gives motivation for optimizing when regen time starts to grow above an acceptable amount.
Profiling
The first step to optimizing a custom feature is to profile your feature. In order to profile a feature, you need to first insert the feature into a part studio (and not have any errrors). Next, in your feature studio select the option to profile the part studio. Its important to note that profiling can be quite slow compared to regeneration time, typically up to 10x slower.
The result of Profiling is a list of all of the slowest calls in the FeatureStudio. The total time and number of calls is shown, along with a colour indicator in how much time was spent on that call compared to the rest of the feature. This is a great place to start because we know where to focus our efforts to make the largest gains.
In the example on the right, we can see our feature takes 422ms to regenerate, but the evDistance call is 340ms of that time.
Tips for performance Increases
In no particular order
Tip 1 - Minimize resource intensive calls
When you start to profile your features, something you will notice is that any call starting with ev or op is almost always going to be most resource intensive call in FeatureScript. These evaluations and operations are either modifying geometry or require a lot of intense math to produce a result. The simplest improvement to be made is simply to think about writing your feature in a way that minimizes these calls. Storing the result of an evDistance is going to be faster than calling it every time you need that value.
Tip 2 - Built in functions
If you go poking around in the Onshape std code, you'll find an interesting type of function starting with @. These functions seem to have no documentation, and you can't control click into them. Thats because these are the "built in" functions. These functions are the lowest level function accessible in FeatureScript. The call is not interpreted by FeatureScript, it gets sent off to the black box of Onshape's back end. Built in functions offer a trade off, improved speed at the cost of ease of use and stability. Onshape wraps most of these functions so the average FeatureScripter has an easy and consistent experience. But if you are looking for gains, here are a few simple swaps to see big improvements.
Regular Function | Built-in | Speed Gain | Caveats |
normalize() *Note this data was collected on an older version of Onshape. Improvements have made this irrelevant | @normalize() | 20-50x | *No longer necessary due to Onshape Updates |
evDistance | @evDistance | 2x | The result distance has no units (its in meters), and the queries are not cast to a Query object |
size | @size | 3-4x | |
evLength | @evLength | 2-3x | The result has no units |
evPlane | @evPlane | 4-5x | The result has no units. Vectors are arrays. How you cast to a vector can change your performance result |
constructPath | @constructPaths | 10-20x | The result query data needs to be manipulated into query objects, losing a bit of speed. |
Tip 3 - Queries
A common beginner mistake in FeatureScript is to evaluate the query when its not required. Queries are a great part of FeatureScript design. Instead of carrying around the heavy load of entity data, the Query is just a set of instructions on how to find the entities you wish to pass into an evaluation or operation. Might seem weird that the query doesn't contain entity data, but by passing instruction into Onshapes back end, the process is much more efficient. Many scripts do not need to ever call evaluateQuery, unless you need to know the current number of elements that a query resolves to.
Building good queries over using evaluated data is good practice in efficient scripts. Consider qLargest vs evaluating the area/volume/length of each entity in a query. qlargest has minimal regen time compared to the effort of calling evArea or evLength many times.
Tip 4 - Skip the units
FeatureScript's 'valueWithUnits' is fantastic. It gets rid of so many headaches in programming for a CAD system, I love it. But it does come with a small performance cost. Any math operation on a valuewithunits takes longer than a primitive value (ie double), as theres always a units translation step. If you are looking to do a bunch of intense math and can keep consistent units, you can see performance gains by not using value with units, and just using primitives. This tip is more relevant if you are also using built ins, as most Onshape operations give back values with units.
Tip 5 - Use Math
FeatureScript makes a lot of the math and CAD development pretty easy, and its part of why FeatureScript is so accessible. But the ease of use shouldn't prevent you from remembering highschool math.
Distance between two points? evDistance? No...
var pointDistance = norm(pointa-pointb);
Tip 6 - Fit Spline is faster than a sketch
Just making a straight line? Skip the sketch and use a two point fit spline.
opFitSpline(context, id + "fitSpline1", {
"points" : [
pointA,
pointB
]
});
Tip 7 - Rethink your inputs
Having a magic feature that automatically finds all of the geometry is a nice to have, but sometimes the fastest feature is the one where a human clicks the right edge for you.
Comments