Closed lostmsu closed 5 years ago
It would be nice to add more comments for the different changes so its easier to understand and assert that the new implementation is equivelent to the previous one.
I don't think it makes sense to do in the code, as the old code will be gone after making this change. Clarified a bit in the review itself though.
As for any performance change, testing and measuring is the key stone, it would be good to add some testing information and results to the PR showcasing the improvements. Also noting how were these changes tested windows/linux, with what etc.
I only tested on a Windows box with sample data from https://github.com/QuantConnect/Lean/tree/master/Data . As suggested by Jared, I run random data generator to fill the date range 2010-2018.
I put the following into config.json
, and run Launcher.
// algorithm class selector
"algorithm-type-name": "C:\\Users\\SCRAMBLED\\Projects\\QuantConnect\\Lean\\Algorithm.Python\\Benchmarks\\IndicatorRibbonBenchmark",
// Algorithm language selector - options CSharp, FSharp, VisualBasic, Python, Java
"algorithm-language": "Python",
//Physical DLL location
"algorithm-location": "../../../Algorithm.Python/Benchmarks/IndicatorRibbonBenchmark.py",
Without the changes I got ~13k dps, and ~17k dps with the changes.
I have also tested (initially) by adding a 128 iteration loop around the body AlgorithmPythonWrapper.OnData
to reduce the effect of data loading on overall run time, and got a decrease from ~35s to ~25s run time as reported by the Launcher (about 5s in both these numbers are spent in data reading).
Wondering if these changes have been presented at https://github.com/pythonnet/pythonnet ?
I will upstream them as soon as I have time for that.
P.S. Completed answering to this pass of review, ready for a new iteration.
@Martin-Molinero dropping Marshal changes improves performance? That looks suspicious.
@Martin-Molinero dropping Marshal changes improves performance? That looks suspicious.
I'd rather say, based on these tests results, that its exposing the fact that the Marshal changes didn't improve performance significantly. There is clearly a dispersion in the result values.
@Martin-Molinero I removed the Marshal
-related change, and squashed the rest to a single commit.
@Martin-Molinero I recommend merging it using Squash and Merge, otherwise a merge commit will be created. Or manually cherry-pick c70724a
food for thought -- It's great seeing the macro-level performance tests, but this repository may also benefit from micro-level speed tests. This will help us track impacts of performance changes on individual operations. For example, this PR seems to directly impact performance of invoking a member (method/property/etc) on a native C# object that has been returned from the python runtime. We could have a performance test that specifically measures this case. Also, we would be able to make better informed decisions regarding improvements on the micro-scale, such as the Marshal
changes (since removed)
@mchandschuh , I created a project in the main Python.NET repo to track benchmarking: https://github.com/pythonnet/pythonnet/projects/5 Since there's no existing infra for it, I think it is out of scope for this change.
Done with this iteration. Note: I haven't made any code changes. If you strongly believe some are required, please respond to one of the conversations.
Hey guys! Any changes required for this to get in?
Various team members getting back from vacation and travels - will be able to test and get in soon.
Merging so we start cloud integration and performance testing. Note: adding a new merge commit to follow existing merging policy.
What does this implement/fix? Explain your changes.
This improves the performance of Python -> C# calls by up to 50%.
Offset calculation for instance unwrapping
Commits 3344110 and 0d158f5 can actually be squashed into one change. They addresses the following scenario:
a
is created and filled with some data.a
is passed via Python.NET to Python. To do that Python.NET creates a wrapper objectw
, and stores reference toa
in one of the its fields.w
back to C#, e.g. callsSomeCSharpMethod(w)
.w
, so it reads the reference toa
from it.Prior to this change in 4. Python.NET had to determine what kind of an object
a
is. If it is an exception, a different offset needed to be used. That check was very expensive (up to 4 calls into Python interpreter).The change replaces that check with computing offset unconditionally from the object size it reads from the wrapper.
Replacing
Marshal.Read*/Marshal.Write*
methods in hot paths 12d1378Marshal
class methods provide safe way to read and write primitive values from unmanaged memory. Safety involves two checks:NullReferenceException
in case pointer isnull
: the contract, provided byMarshal
class requires that to be converted toAccessViolationException
.Both are expensive, and not needed in Python.NET
Marshal
.So a couple of methods are added to
Util
class to perform faster unmanaged memory access, andMarshal
calls replaced with them in hot paths (mostly inCLRObject
constructor).Does this close any currently open issues?
N/A
Any other comments?
N/A
Checklist
Check all those that are applicable and complete.
AUTHORS
CHANGELOG