Commit 4b99b6b
authored
DYN-6615: Optimize 'Element.GetParameterByName' node (#3261)
### Purpose
This PR addresses [DYN-6615](https://jira.autodesk.com/browse/DYN-6615)
by optimizing `Element.GetParameterByName` to fix a significant
performance bottleneck when processing large numbers of elements (50K+).
The issue was identified through profiling which revealed that 58% of
execution time was spent in Revit API's `ParameterSet.Insert`
operations, triggered by enumerating all parameters via
`InternalElement.Parameters` on every call.
**Root Cause Analysis:**
- `Element.GetParameterByName` was called 50K+ times during graph
execution
- Each call enumerated all parameters via `InternalElement.Parameters`,
which triggers expensive Revit API `ParameterSet.Insert` operations
- Profiling showed this was the primary hot path (58% of total execution
time)
**Solution:**
The optimization replaces manual parameter enumeration
(`InternalElement.Parameters`) with `GetParameters(string name)`, which
is optimized by the Revit API to filter parameters by name without
building the entire parameter collection. This avoids the expensive
`ParameterSet.Insert` operations that occur when enumerating all
parameters. Both the original implementation and `GetParameters(string)`
use case-sensitive comparison (`string.CompareOrdinal`), ensuring
identical behavior while providing significant performance improvements.
**Performance Impact:**
Performance testing was conducted using Dynamo TuneUp extension
(end-to-end node execution including Dynamo engine/DesignScript VM
overhead) with 50,000 element operations. Three approaches were
evaluated:
- **Unoptimized**: Manual enumeration via `InternalElement.Parameters`
with LINQ filtering (original implementation)
- **LookupParameter**: Using `InternalElement.LookupParameter(string)`
for direct parameter lookup
- **GetParameters**: Using `InternalElement.GetParameters(string)` to
filter parameters by name (chosen solution)
| Method | Run 1 (ms) | Run 2 (ms) | Run 3 (ms) | Average (ms) |
Improvement vs Unoptimized | Speedup Factor |
| ------------------- | ---------- | ---------- | ---------- |
------------- | -------------------------- | -------------- |
| **Unoptimized** | 66,288 | 65,438 | 66,710 | **66,145.33** | Baseline
| 1.0x |
| **LookupParameter** | 3,800 | 3,824 | 3,810 | **3,811.33** | **94.2%
faster** | **17.4x** |
| **GetParameters** | 3,958 | 3,983 | 3,963 | **3,968.00** | **94.0%
faster** | **16.7x** |
**Summary:**
- **~17x faster** using `GetParameters(string)` compared to manual
enumeration
- **~94% reduction** in execution time
- **~62 seconds saved** per 50K element operation
- `GetParameters(string)` was chosen over `LookupParameter(string)` as
both show virtually identical performance (~3.8-4.0 seconds vs ~66
seconds), and `GetParameters` provides better handling of duplicate
parameter names
- **Backward compatibility maintained**: Both the original
implementation and `GetParameters` use case-sensitive comparison
(`string.CompareOrdinal`), ensuring identical behavior and no regression
for existing graphs
The implementation maintains backward compatibility by preserving the
original behavior (case-sensitive matching, duplicate parameter names,
read-only parameter handling) while optimizing performance through the
Revit API's efficient parameter filtering.
### Declarations
Check these if you believe they are true
- [x] The code base is in a better state after this PR
- [x] Is documented according to the
[standards](https://github.com/DynamoDS/Dynamo/wiki/Coding-Standards)
- [x] The level of testing this PR includes is appropriate
- [x] User facing strings, if any, are extracted into `*.resx` files
- [ ] Snapshot of UI changes, if any. (N/A - No UI changes)
### Reviewers
(FILL ME IN) Reviewer 1 (If possible, assign the Reviewer for the PR)
**Test Methodology:**
- Performance testing was conducted with 50,000 element operations
- Multiple test runs were performed to ensure consistency
- Results are documented in `logs/notes.md`
**Implementation Details:**
- Uses `GetParameters(string)` which is optimized by Revit API to filter
by parameter name
- Maintains case-sensitive comparison (same as original
`string.CompareOrdinal` behavior)
- Handles duplicate parameter names and read-only parameters correctly
(prefers writable parameters)
- Maintains identical behavior and return values with the original
implementation
### FYIs
(FILL ME IN, Optional) Names of anyone else you wish to be notified of1 parent 27c2c58 commit 4b99b6b
1 file changed
+13
-12
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
430 | 430 | | |
431 | 431 | | |
432 | 432 | | |
433 | | - | |
434 | | - | |
435 | | - | |
436 | | - | |
437 | | - | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
438 | 437 | | |
439 | | - | |
440 | | - | |
441 | | - | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
442 | 445 | | |
443 | 446 | | |
444 | | - | |
445 | | - | |
446 | | - | |
| 447 | + | |
447 | 448 | | |
448 | 449 | | |
449 | 450 | | |
| |||
1354 | 1355 | | |
1355 | 1356 | | |
1356 | 1357 | | |
1357 | | - | |
| 1358 | + | |
0 commit comments