Skip to content

Commit d14105d

Browse files
authored
Merge branch 'master' into losttech-perf-interop
2 parents d0d7545 + 2736094 commit d14105d

24 files changed

+924
-28
lines changed

.editorconfig

+11
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@ indent_size = 2
1919
[*.{csproj,pyproj,config}]
2020
indent_size = 2
2121

22+
# .NET formatting settings
23+
[*.{cs,vb}]
24+
dotnet_sort_system_directives_first = true
25+
dotnet_separate_import_directive_groups = true
26+
27+
[*.cs]
28+
csharp_new_line_before_open_brace = true
29+
csharp_new_line_before_else = true
30+
csharp_new_line_before_catch = true
31+
csharp_new_line_before_finally = true
32+
2233
# Solution
2334
[*.sln]
2435
indent_style = tab

AUTHORS.md

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## Contributors
1414

15+
- Alex Helms ([@alexhelms](https://github.com/alexhelms))
1516
- Alexandre Catarino([@AlexCatarino](https://github.com/AlexCatarino))
1617
- Arvid JB ([@ArvidJB](https://github.com/ArvidJB))
1718
- Benoît Hudson ([@benoithudson](https://github.com/benoithudson))
@@ -41,6 +42,7 @@
4142
- Luke Stratman ([@lstratman](https://github.com/lstratman))
4243
- Konstantin Posudevskiy ([@konstantin-posudevskiy](https://github.com/konstantin-posudevskiy))
4344
- Matthias Dittrich ([@matthid](https://github.com/matthid))
45+
- Mohamed Koubaa ([@koubaa](https://github.com/koubaa))
4446
- Patrick Stewart ([@patstew](https://github.com/patstew))
4547
- Raphael Nestler ([@rnestler](https://github.com/rnestler))
4648
- Rickard Holmberg ([@rickardraysearch](https://github.com/rickardraysearch))

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1010
### Added
1111

1212
- Added automatic NuGet package generation in appveyor and local builds
13+
- Added function that sets Py_NoSiteFlag to 1.
14+
- Added support for Jetson Nano.
1315

1416
### Changed
1517

@@ -47,6 +49,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
4749
- Added PyObject finalizer support, Python objects referred by C# can be auto collect now ([#692][p692]).
4850
- Added detailed comments about aproaches and dangers to handle multi-app-domains ([#625][p625])
4951
- Python 3.7 support, builds and testing added. Defaults changed from Python 3.6 to 3.7 ([#698][p698])
52+
- Added support for C# types to provide `__repr__` ([#680][p680])
5053

5154
### Changed
5255

README.rst

+8
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ projects using pythonnet can be found in the Wiki:
9595

9696
https://github.com/pythonnet/pythonnet/wiki
9797

98+
Python 3.8.0 support
99+
--------------------
100+
101+
Some features are disabled in Python 3.8.0 because of
102+
`this bug in Python <https://bugs.python.org/issue37633>`_. The error is
103+
``System.EntryPointNotFoundException : Unable to find an entry point named
104+
'Py_CompileString' in DLL 'python38'``. This will be fixed in Python 3.8.1.
105+
98106
.. |Join the chat at https://gitter.im/pythonnet/pythonnet| image:: https://badges.gitter.im/pythonnet/pythonnet.svg
99107
:target: https://gitter.im/pythonnet/pythonnet?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
100108
.. |appveyor shield| image:: https://img.shields.io/appveyor/ci/pythonnet/pythonnet/master.svg?label=AppVeyor

appveyor.yml

+6
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,22 @@ environment:
2323
BUILD_OPTS: --xplat
2424
- PYTHON_VERSION: 3.7
2525
BUILD_OPTS: --xplat
26+
- PYTHON_VERSION: 3.8
27+
BUILD_OPTS: --xplat
2628
- PYTHON_VERSION: 2.7
2729
- PYTHON_VERSION: 3.5
2830
- PYTHON_VERSION: 3.6
2931
- PYTHON_VERSION: 3.7
32+
- PYTHON_VERSION: 3.8
3033

3134
matrix:
3235
allow_failures:
3336
- PYTHON_VERSION: 3.4
3437
BUILD_OPTS: --xplat
3538
- PYTHON_VERSION: 3.4
39+
- PYTHON_VERSION: 3.8
40+
BUILD_OPTS: --xplat
41+
- PYTHON_VERSION: 3.8
3642

3743
init:
3844
# Update Environment Variables based on matrix/platform

pythonnet.15.sln

+184-7
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
6+
using Python.Runtime;
7+
8+
namespace Python.PerformanceTests
9+
{
10+
public class BaselineComparisonBenchmarkBase
11+
{
12+
public BaselineComparisonBenchmarkBase()
13+
{
14+
Console.WriteLine($"CWD: {Environment.CurrentDirectory}");
15+
Console.WriteLine($"Using Python.Runtime from {typeof(PythonEngine).Assembly.Location} {typeof(PythonEngine).Assembly.GetName()}");
16+
17+
try {
18+
PythonEngine.Initialize();
19+
Console.WriteLine("Python Initialized");
20+
if (PythonEngine.BeginAllowThreads() == IntPtr.Zero)
21+
throw new PythonException();
22+
Console.WriteLine("Threading enabled");
23+
}
24+
catch (Exception e) {
25+
Console.WriteLine(e);
26+
throw;
27+
}
28+
}
29+
30+
static BaselineComparisonBenchmarkBase()
31+
{
32+
string pythonRuntimeDll = Environment.GetEnvironmentVariable(BaselineComparisonConfig.EnvironmentVariableName);
33+
if (string.IsNullOrEmpty(pythonRuntimeDll))
34+
{
35+
throw new ArgumentException(
36+
"Required environment variable is missing",
37+
BaselineComparisonConfig.EnvironmentVariableName);
38+
}
39+
40+
Console.WriteLine("Preloading " + pythonRuntimeDll);
41+
Assembly.LoadFrom(pythonRuntimeDll);
42+
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) {
43+
if (assembly.FullName.StartsWith("Python.Runtime"))
44+
Console.WriteLine(assembly.Location);
45+
foreach(var dependency in assembly.GetReferencedAssemblies())
46+
if (dependency.FullName.Contains("Python.Runtime")) {
47+
Console.WriteLine($"{assembly} -> {dependency}");
48+
}
49+
}
50+
51+
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve;
52+
}
53+
54+
static Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args) {
55+
if (!args.Name.StartsWith("Python.Runtime"))
56+
return null;
57+
58+
var preloaded = AppDomain.CurrentDomain.GetAssemblies()
59+
.FirstOrDefault(a => a.GetName().Name == "Python.Runtime");
60+
if (preloaded != null) return preloaded;
61+
62+
string pythonRuntimeDll = Environment.GetEnvironmentVariable(BaselineComparisonConfig.EnvironmentVariableName);
63+
if (string.IsNullOrEmpty(pythonRuntimeDll))
64+
return null;
65+
66+
return Assembly.LoadFrom(pythonRuntimeDll);
67+
}
68+
}
69+
}
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Reflection;
5+
6+
using BenchmarkDotNet.Configs;
7+
using BenchmarkDotNet.Jobs;
8+
9+
namespace Python.PerformanceTests
10+
{
11+
public class BaselineComparisonConfig : ManualConfig
12+
{
13+
public const string EnvironmentVariableName = "PythonRuntimeDLL";
14+
15+
public BaselineComparisonConfig()
16+
{
17+
this.Options |= ConfigOptions.DisableOptimizationsValidator;
18+
19+
string deploymentRoot = BenchmarkTests.DeploymentRoot;
20+
21+
var baseJob = Job.Default;
22+
this.Add(baseJob
23+
.WithId("baseline")
24+
.WithEnvironmentVariable(EnvironmentVariableName,
25+
Path.Combine(deploymentRoot, "baseline", "Python.Runtime.dll"))
26+
.WithBaseline(true));
27+
this.Add(baseJob
28+
.WithId("new")
29+
.WithEnvironmentVariable(EnvironmentVariableName,
30+
Path.Combine(deploymentRoot, "new", "Python.Runtime.dll")));
31+
}
32+
33+
static BaselineComparisonConfig() {
34+
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve;
35+
}
36+
37+
static Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args) {
38+
Console.WriteLine(args.Name);
39+
if (!args.Name.StartsWith("Python.Runtime"))
40+
return null;
41+
string pythonRuntimeDll = Environment.GetEnvironmentVariable(EnvironmentVariableName);
42+
if (string.IsNullOrEmpty(pythonRuntimeDll))
43+
pythonRuntimeDll = Path.Combine(BenchmarkTests.DeploymentRoot, "baseline", "Python.Runtime.dll");
44+
return Assembly.LoadFrom(pythonRuntimeDll);
45+
}
46+
}
47+
}

src/perf_tests/BenchmarkTests.cs

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Runtime.CompilerServices;
6+
using System.Reflection;
7+
8+
using BenchmarkDotNet.Reports;
9+
using BenchmarkDotNet.Running;
10+
using NUnit.Framework;
11+
12+
namespace Python.PerformanceTests
13+
{
14+
public class BenchmarkTests
15+
{
16+
Summary summary;
17+
18+
[OneTimeSetUp]
19+
public void SetUp()
20+
{
21+
Environment.CurrentDirectory = Path.Combine(DeploymentRoot, "new");
22+
this.summary = BenchmarkRunner.Run<PythonCallingNetBenchmark>();
23+
Assert.IsNotEmpty(this.summary.Reports);
24+
Assert.IsTrue(this.summary.Reports.All(r => r.Success));
25+
}
26+
27+
[Test]
28+
public void ReadInt64Property()
29+
{
30+
double optimisticPerfRatio = GetOptimisticPerfRatio(this.summary.Reports);
31+
Assert.LessOrEqual(optimisticPerfRatio, 0.68);
32+
}
33+
34+
[Test]
35+
public void WriteInt64Property()
36+
{
37+
double optimisticPerfRatio = GetOptimisticPerfRatio(this.summary.Reports);
38+
Assert.LessOrEqual(optimisticPerfRatio, 0.66);
39+
}
40+
41+
static double GetOptimisticPerfRatio(
42+
IReadOnlyList<BenchmarkReport> reports,
43+
[CallerMemberName] string methodName = null)
44+
{
45+
reports = reports.Where(r => r.BenchmarkCase.Descriptor.WorkloadMethod.Name == methodName).ToArray();
46+
if (reports.Count == 0)
47+
throw new ArgumentException(
48+
message: $"No reports found for {methodName}. "
49+
+ "You have to match test method name to benchmark method name or "
50+
+ "pass benchmark method name explicitly",
51+
paramName: nameof(methodName));
52+
53+
var baseline = reports.Single(r => r.BenchmarkCase.Job.ResolvedId == "baseline").ResultStatistics;
54+
var @new = reports.Single(r => r.BenchmarkCase.Job.ResolvedId != "baseline").ResultStatistics;
55+
56+
double newTimeOptimistic = @new.Mean - (@new.StandardDeviation + baseline.StandardDeviation) * 0.5;
57+
58+
return newTimeOptimistic / baseline.Mean;
59+
}
60+
61+
public static string DeploymentRoot => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net461</TargetFramework>
5+
<Configurations>DebugMono;DebugMonoPY3;ReleaseMono;ReleaseMonoPY3;DebugWin;DebugWinPY3;ReleaseWin;ReleaseWinPY3</Configurations>
6+
7+
<IsPackable>false</IsPackable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" />
12+
<PackageReference Include="nunit" Version="3.12.0" />
13+
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
14+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
15+
<PackageReference Include="pythonnet" Version="2.3.0" GeneratePathProperty="true">
16+
<IncludeAssets>compile</IncludeAssets>
17+
</PackageReference>
18+
</ItemGroup>
19+
20+
<Target Name="GetRuntimeLibBuildOutput" BeforeTargets="Build">
21+
<MSBuild Projects="..\runtime\Python.Runtime.15.csproj" Properties="PYTHONNET_PY3_VERSION=PYTHON35;Configuration=$(Configuration);TargetFramework=net40;Python3Version=PYTHON35;OutputPath=bin\for_perf\">
22+
<Output TaskParameter="TargetOutputs" ItemName="NewPythonRuntime" />
23+
</MSBuild>
24+
</Target>
25+
26+
<Target Name="CopyBaseline" AfterTargets="Build">
27+
<Copy SourceFiles="$(Pkgpythonnet)\lib\net40\Python.Runtime.dll" DestinationFolder="$(OutDir)\baseline" />
28+
</Target>
29+
30+
<Target Name="CopyNewBuild" AfterTargets="Build">
31+
<Copy SourceFiles="@(NewPythonRuntime)" DestinationFolder="$(OutDir)\new" />
32+
</Target>
33+
34+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
using BenchmarkDotNet.Attributes;
6+
using Python.Runtime;
7+
8+
namespace Python.PerformanceTests
9+
{
10+
[Config(typeof(BaselineComparisonConfig))]
11+
public class PythonCallingNetBenchmark: BaselineComparisonBenchmarkBase
12+
{
13+
[Benchmark]
14+
public void ReadInt64Property()
15+
{
16+
using (Py.GIL())
17+
{
18+
var locals = new PyDict();
19+
locals.SetItem("a", new NetObject().ToPython());
20+
PythonEngine.Exec($@"
21+
s = 0
22+
for i in range(300000):
23+
s += a.{nameof(NetObject.LongProperty)}
24+
", locals: locals.Handle);
25+
}
26+
}
27+
28+
[Benchmark]
29+
public void WriteInt64Property() {
30+
using (Py.GIL()) {
31+
var locals = new PyDict();
32+
locals.SetItem("a", new NetObject().ToPython());
33+
PythonEngine.Exec($@"
34+
s = 0
35+
for i in range(300000):
36+
a.{nameof(NetObject.LongProperty)} += i
37+
", locals: locals.Handle);
38+
}
39+
}
40+
}
41+
42+
class NetObject
43+
{
44+
public long LongProperty { get; set; } = 42;
45+
}
46+
}

src/runtime/Python.Runtime.15.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<Python2Version>$(PYTHONNET_PY2_VERSION)</Python2Version>
4343
<Python2Version Condition="'$(Python2Version)'==''">PYTHON27</Python2Version>
4444
<Python3Version>$(PYTHONNET_PY3_VERSION)</Python3Version>
45-
<Python3Version Condition="'$(Python3Version)'==''">PYTHON37</Python3Version>
45+
<Python3Version Condition="'$(Python3Version)'==''">PYTHON38</Python3Version>
4646
<PythonWinDefineConstants>$(PYTHONNET_WIN_DEFINE_CONSTANTS)</PythonWinDefineConstants>
4747
<PythonWinDefineConstants Condition="'$(PythonWinDefineConstants)'==''">UCS2</PythonWinDefineConstants>
4848
<PythonMonoDefineConstants>$(PYTHONNET_MONO_DEFINE_CONSTANTS)</PythonMonoDefineConstants>

0 commit comments

Comments
 (0)