Rhino 8 Regression: CPython/IronPython RhinoCommon Performance Is Worse

Hi McNeel,

I’ve noticed that CPython scripts will perform substantially worse when implementing RhinoCommon than IronPython (presumably because of Python.NET) . And that the new script editor with IronPython performs slightly worse than GHPython (presumably because of the new editor, since they’re both running 2.7.12 .NETCoreApp). Here’s a quick demonstration making a whole bunch of Point3d within for loops:


230801_ScriptsMillionPoints_00.gh (10.6 KB)

Best,

Anders

1 Like

I’m not sure regression is the best term. No old tests are being failed, are they?

Is this a fairly niche benchmark, that shows the trade off between using CPython (that allows access to numpy and perhaps even numba, for traditional optimised CPython workflows), and using CPython for the sake of CPython, even where calling out is an unncessary extra step, just to achieve the goal of creating native Rhino Points (implemented in .Net).

1 Like

The new thing(s) work worse than the old thing. We’ve typically referred to that as a regression here on the forum, but I’m not a native English speaker.

I’m not sure how any of that is relevant to what is being reported. If McNeel is unaware of this substantially worse CPython performance, and there might be a solution to it, that seems important for Rhino/Python users. Especially if there is some notion to entirely drop IronPython in favour of CPython down the road.

2 Likes

Hi Anders, Your English is great! People just misuse these terms all the time (myself included) so no harm done.

But FYI in software, a “regression” also has a specific meaning: Software regression - Wikipedia regression". It’s much worse, than performance of an old feature still being better than a new one.

if there is some notion to entirely drop IronPython in favour of CPython down the road.

Dropping Iron Python 2 in favour of CPython 3 could break a substantial number of the Python plug-ins on food4rhino. That would be one heck of a regression (and is an excellent example of when “regression” is far too polite a term)!

1 Like

Speed decreases are also considered regressions, IMHO.

3 Likes

@AndersDeleuran

CPython vs IronPython

CPython implementation in Rhino 8 (Custom implementation of Pythonnet and hereon refered to as Pythonnet) is NOT meant to replace IronPython. These are two completely different implementations of the Python language specification. Each have their own pros and cons:

  • IronPython compiles to dotnet common language runtime (CLR) bytecode, and uses the same type system and managed memory as dotnet runtime and therefore is incredibaly fast once the runtime is loaded. But it does not implement the CPython C-API which means it can not load python modules like numpy or scipy that are built on top of this api. IronPython might also be better for multi-threading as it does not have the Global Interpretter Lock (GIL) that CPython has, and it uses the dotnet runtime Task and Threading libraries.

  • Pythonnet on the other hand is there to provide a more modern python syntax and access to numerical and machine learning packages inside a dotnet application. I’d appreciate if you can show me any other dotnet application that has a faster CPython implementation, that also provides debugging, and package management:

    • Method Binding: Let’s say you want to call .ClosestPoint() on a Brep instance that has a few overloads. Which overload to call depends on the number and types of arguments that are being passed to the method. IronPython does not have to spend a lot of time figuring out which method to call since it is basically using the dotnet runtime infrastructure that makes those resolutions and it is fast. Pythonnet on the other hand has a custom method binder since its data types and handlers are not known to dotnet and it needs to make these decisions internally. Therefore it is a lot slower in calling dotnet methods BUT it makes it possible! Something that wasn’t available before.

+ For Rhino 8.5 RC I have a fresh method binder that we have written from scratch. It does a much better job at figuring out how to match given arguments to the many possible overloads and choose one. It is also a little bit faster that the current binder in Rhino 8.4, especially as the number of arguments increases.

+ For Rhino 8.5 RC I also have implemented the clr.StrongBox that makes it easier to specify which ref or out parameter should be used.

+ We are also planning to support rhino3dm in CPython inside if Rhino for faster access to Rhino native APIs from Python.

Scripting Tools

Yes currently the new IronPython script component is just slightly slower than the old one. But have you noticed you can debug your scripts and even the ScriptInstance methods? The new component does more and is consistent across languages. Yes we will make it faster over time or you will buy slightly faster cpus so for now I would call that a reasonable compromise.

I’d apprciate to know anything about the new script editor or script component that is stopping you from being productive. I doubt a few milliseconds on creating a million points is one of those. But let me know if it is and we will improve.

5 Likes

Sure. Performance may be tested.

But not speed differences between one tool and a different tool (even if they happen to support the same language)?

Cheers @eirannejad, thanks for the breakdown. Some quick feedback:

Regarding CPython Performance:

I’ve been around since the Enthought 32 bit numpy days, so I’m very excited to finally have native CPython support. That said, I have not seen any performance reports on the forum yet, only regressions regarding RhinoCommon and rhinoscriptsyntax API breakages. So if you (McNeel) or one (us users) weren’t aware of this potentially quite severe .NET interop performance penalty, that seems like potentially important information when starting up a new project or porting over code from GHPython (i.e. when choosing between IronPython and CPython). It’s good to hear that this penalty might be mitigated, but perhaps it’s also information that ought be included in the Rhino Python and new script editor documentation.

Regarding IronPython Performance:

It’s great to have it confirmed that IronPython will not be dropped. And that GHPython is still included, though it’s currently borked. Unfortunately there has been a history of performance regression with GHPython. Most notably going from Rhino 5 to Rhino 6/7. Where the IronPython version changed, which led to notably worse performance. And the look-and-feel of the editor was updated, leading to severe breaking functionality. I understand and appreciate the desire to add new and shiny features. Especially when those are actually useful in practice (e.g. the debugger). But my personal preference will always be on snappiness and performance (I’m the type that toggles PS5 games from fidelity to performance). So I would expect and prefer the new IronPython editor to be at least as performant and snappy as GHPython (including loading the plugin, which is currently quite slow as well). Can I accept a minor performance regression for features I’d like/use, absolutely. But I’m not entirely convinced yet that it is minor. Here are eight test runs with the file above, where the average compute time is 157% longer with the new IronPython component, compared to GHPython. That’s not a trivial increase, in practice, in my experience:

Performance Test Screenshots








System Information

Rhino 8 SR4 2024-1-23 (Rhino 8, 8.4.24023.15001, Git hash:master @ e0f90d20c78f2125a0ec9cfffc9d9decbc052c01)
License type: Commercial, build 2024-01-23
License details: Cloud Zoo

Windows 11 (10.0.22631 SR0.0) or greater (Physical RAM: 32GB)
.NET 7.0.15

Computer platform: LAPTOP - Plugged in [100% battery remaining]

Hybrid graphics configuration.
Primary display: Intel(R) Iris(R) Xe Graphics (Intel) Memory: 1GB, Driver date: 11-7-2023 (M-D-Y).
> Integrated graphics device with 4 adapter port(s)
- Windows Main Display is laptop’s integrated screen or built-in port
Primary OpenGL: NVIDIA RTX 2000 Ada Generation Laptop GPU (NVidia) Memory: 8GB, Driver date: 6-26-2023 (M-D-Y). OpenGL Ver: 4.6.0 NVIDIA 536.45
> Integrated accelerated graphics device (shares primary device ports)
- Video pass-through to primary display device

OpenGL Settings
Safe mode: Off
Use accelerated hardware modes: On
Redraw scene when viewports are exposed: On
Graphics level being used: OpenGL 4.6 (primary GPU’s maximum)

Anti-alias mode: 8x
Mip Map Filtering: Linear
Anisotropic Filtering Mode: High

Vendor Name: NVIDIA Corporation
Render version: 4.6
Shading Language: 4.60 NVIDIA
Driver Date: 6-26-2023
Driver Version: 31.0.15.3645
Maximum Texture size: 32768 x 32768
Z-Buffer depth: 24 bits
Maximum Viewport size: 32768 x 32768
Total Video Memory: 8188 MB

Rhino plugins that do not ship with Rhino

Rhino plugins that ship with Rhino
C:\Program Files\Rhino 8\Plug-ins\Commands.rhp “Commands” 8.4.24023.15001
C:\Program Files\Rhino 8\Plug-ins\rdk.rhp “Renderer Development Kit”
C:\Program Files\Rhino 8\Plug-ins\RhinoRenderCycles.rhp “Rhino Render” 8.4.24023.15001
C:\Program Files\Rhino 8\Plug-ins\rdk_etoui.rhp “RDK_EtoUI” 8.4.24023.15001
C:\Program Files\Rhino 8\Plug-ins\NamedSnapshots.rhp “Snapshots”
C:\Program Files\Rhino 8\Plug-ins\MeshCommands.rhp “MeshCommands” 8.4.24023.15001
C:\Program Files\Rhino 8\Plug-ins\RhinoCycles.rhp “RhinoCycles” 8.4.24023.15001
C:\Program Files\Rhino 8\Plug-ins\Grasshopper\GrasshopperPlugin.rhp “Grasshopper” 8.4.24023.15001
C:\Program Files\Rhino 8\Plug-ins\RhinoCode\RhinoCodePlugin.rhp “RhinoCodePlugin” 8.4.24023.15001
C:\Program Files\Rhino 8\Plug-ins\Toolbars\Toolbars.rhp “Toolbars” 8.4.24023.15001
C:\Program Files\Rhino 8\Plug-ins\3dxrhino.rhp “3Dconnexion 3D Mouse”
C:\Program Files\Rhino 8\Plug-ins\Displacement.rhp “Displacement”
C:\Program Files\Rhino 8\Plug-ins\SectionTools.rhp “SectionTools”

Regarding Productivity Issues:

It’s honestly mainly the look-and-feel design issues we’ve been discussing, which are preventing me from adopting the new editor (edit: and this performance issue). While those may seem silly, a quite serious one for me in terms of productivity is the issue of code/text legibility (i.e. due to font rendering and syntax highlighting). Where the new editor simply isn’t working for my eyes/brain. I’ll start a new topic elaborating in this when I find some time. And again, thanks so much for implementing a lot of these design suggestions :pray:

3 Likes

Hi @eirannejad, just replying to your performance test post over here: I tried expanding your test with my usual “performance matrix” of cross checking run times with/without implicit cycles, type hints, and Grasshopper types. And the results look fairly predictable/similar to GHPython:


240610_EhsanPerformanceTest_WithCycleTypeHintAndCPy_00.gh (16.1 KB)

So while implicit cycles and type hints definitely have an impact on performance with the new scripting components, there does indeed seem to be something else going on that makes IronPython slower than GHPython. As far as I can tell, they implement the same version of IronPython, so that’s probably not it (i.e. as was the case with the quite drastic Rhino 5 to 6 performance drop).

1 Like

Looking into this, I don’t see anything immediate jumping out so I won’t put any fixes in 8.8. The new component does much more than previous so there is a little fluff around it that starts showing up when it is ran 10_000 times.

I will look deeper at the fluff and try to trim it down for performance. I can still see the recent changes has made it slightly slower and it shows up in my original perf tests.

RH-82474 New IronPython is much slower than legacy GHPython

1 Like