Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 741070b

Browse files
author
dse
committed
Python string to CLR string marshaling cache added.
1 parent 507edc9 commit 741070b

9 files changed

+531
-5
lines changed

src/runtime/Python.Runtime.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@
7676
<Reference Include="System" />
7777
</ItemGroup>
7878
<ItemGroup>
79+
<Compile Include="perf_utils\EncodedStringsFifoDictionary.cs" />
80+
<Compile Include="perf_utils\EncodingGetStringPolyfill.cs" />
81+
<Compile Include="perf_utils\FifoDictionary.cs" />
82+
<Compile Include="perf_utils\RawImmutableMemBlock.cs" />
83+
<Compile Include="perf_utils\RawMemoryFifoDictionary.cs" />
84+
<Compile Include="perf_utils\RawMemUtils.cs" />
7985
<Compile Include="Properties\AssemblyInfo.cs" />
8086
<Compile Include="..\SharedAssemblyInfo.cs">
8187
<Link>Properties\SharedAssemblyInfo.cs</Link>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System;
2+
3+
namespace Python.Runtime
4+
{
5+
using System.Runtime.InteropServices;
6+
7+
public class EncodedStringsFifoDictionary: IDisposable
8+
{
9+
private readonly FifoDictionary<string, IntPtr> _innerDictionary;
10+
11+
private readonly IntPtr _rawMemory;
12+
13+
private readonly int _allocatedSize;
14+
15+
public EncodedStringsFifoDictionary(int capacity, int maxItemSize)
16+
{
17+
if (maxItemSize < 1)
18+
{
19+
throw new ArgumentOutOfRangeException(
20+
nameof(maxItemSize),
21+
"Maximum item size should be non-zero positive.");
22+
}
23+
24+
_innerDictionary = new FifoDictionary<string, IntPtr>(capacity);
25+
_allocatedSize = maxItemSize * capacity;
26+
_rawMemory = Marshal.AllocHGlobal(_allocatedSize);
27+
28+
MaxItemSize = maxItemSize;
29+
}
30+
31+
public int MaxItemSize { get; }
32+
33+
public bool TryGetValue(string key, out IntPtr value)
34+
{
35+
return _innerDictionary.TryGetValue(key, out value);
36+
}
37+
38+
public IntPtr AddUnsafe(string key)
39+
{
40+
int nextSlot = _innerDictionary.NextSlotToAdd;
41+
IntPtr ptr = _rawMemory + (MaxItemSize * nextSlot);
42+
_innerDictionary.AddUnsafe(key, ptr);
43+
return ptr;
44+
}
45+
46+
public bool IsKnownPtr(IntPtr ptr)
47+
{
48+
var uptr = (ulong)ptr;
49+
var umem = (ulong)_rawMemory;
50+
51+
return uptr >= umem && uptr < umem + (ulong)_allocatedSize;
52+
}
53+
54+
private void ReleaseUnmanagedResources()
55+
{
56+
if (_rawMemory != IntPtr.Zero)
57+
{
58+
Marshal.FreeHGlobal(_rawMemory);
59+
}
60+
}
61+
62+
public void Dispose()
63+
{
64+
ReleaseUnmanagedResources();
65+
GC.SuppressFinalize(this);
66+
}
67+
68+
~EncodedStringsFifoDictionary()
69+
{
70+
ReleaseUnmanagedResources();
71+
}
72+
}
73+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Reflection;
4+
using System.Runtime.InteropServices;
5+
using System.Text;
6+
7+
namespace Python.Runtime
8+
{
9+
/// <summary>
10+
/// This polyfill is thread unsafe.
11+
/// </summary>
12+
#if !NETSTANDARD
13+
public static class EncodingGetStringPolyfill
14+
{
15+
private static readonly MethodInfo PlatformGetStringMethodInfo =
16+
typeof(Encoding).GetMethod(
17+
"GetString",
18+
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null,
19+
new[]
20+
{
21+
typeof(byte*), typeof(int)
22+
}, null);
23+
24+
private static readonly byte[] StdDecodeBuffer = PlatformGetStringMethodInfo == null ? new byte[1024 * 1024] : null;
25+
26+
private static Dictionary<Encoding, EncodingGetStringUnsafeDelegate> PlatformGetStringMethodsDelegatesCache = new Dictionary<Encoding, EncodingGetStringUnsafeDelegate>();
27+
28+
private unsafe delegate string EncodingGetStringUnsafeDelegate(byte* pstr, int size);
29+
30+
public unsafe static string GetString(this Encoding encoding, byte* pstr, int size)
31+
{
32+
if (PlatformGetStringMethodInfo != null)
33+
{
34+
EncodingGetStringUnsafeDelegate getStringDelegate;
35+
if (!PlatformGetStringMethodsDelegatesCache.TryGetValue(encoding, out getStringDelegate))
36+
{
37+
getStringDelegate =
38+
(EncodingGetStringUnsafeDelegate)PlatformGetStringMethodInfo.CreateDelegate(
39+
typeof(EncodingGetStringUnsafeDelegate), encoding);
40+
PlatformGetStringMethodsDelegatesCache.Add(encoding, getStringDelegate);
41+
}
42+
return getStringDelegate(pstr, size);
43+
}
44+
45+
byte[] buffer = size <= StdDecodeBuffer.Length ? StdDecodeBuffer : new byte[size];
46+
Marshal.Copy((IntPtr)pstr, buffer, 0, size);
47+
return encoding.GetString(buffer, 0, size);
48+
}
49+
}
50+
#endif
51+
52+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System;
2+
3+
namespace Python.Runtime
4+
{
5+
using System.Collections.Generic;
6+
7+
public class FifoDictionary<TKey, TValue>
8+
{
9+
private readonly Dictionary<TKey, int> _innerDictionary;
10+
11+
private readonly KeyValuePair<TKey,TValue>[] _fifoList;
12+
13+
private bool _hasEmptySlots = true;
14+
15+
public FifoDictionary(int capacity)
16+
{
17+
if (capacity <= 0)
18+
{
19+
throw new ArgumentOutOfRangeException(nameof(capacity), "Capacity should be non-zero positive.");
20+
}
21+
22+
_innerDictionary = new Dictionary<TKey, int>(capacity);
23+
_fifoList = new KeyValuePair<TKey, TValue>[capacity];
24+
25+
Capacity = capacity;
26+
}
27+
28+
public bool TryGetValue(TKey key, out TValue value)
29+
{
30+
int index;
31+
if (_innerDictionary.TryGetValue(key, out index))
32+
{
33+
value =_fifoList[index].Value;
34+
return true;
35+
}
36+
37+
value = default(TValue);
38+
return false;
39+
}
40+
41+
public void AddUnsafe(TKey key, TValue value)
42+
{
43+
if (!_hasEmptySlots)
44+
{
45+
_innerDictionary.Remove(_fifoList[NextSlotToAdd].Key);
46+
}
47+
48+
_innerDictionary.Add(key, NextSlotToAdd);
49+
_fifoList[NextSlotToAdd] = new KeyValuePair<TKey, TValue>(key, value);
50+
51+
NextSlotToAdd++;
52+
if (NextSlotToAdd >= Capacity)
53+
{
54+
_hasEmptySlots = false;
55+
NextSlotToAdd = 0;
56+
}
57+
}
58+
59+
public int NextSlotToAdd { get; private set; }
60+
public int Capacity { get; }
61+
}
62+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
namespace Python.Runtime
2+
{
3+
using System;
4+
5+
public struct RawImmutableMemBlock: IEquatable<RawImmutableMemBlock>
6+
{
7+
private readonly int _hash;
8+
9+
public RawImmutableMemBlock(IntPtr ptr, int size)
10+
{
11+
if (ptr == IntPtr.Zero)
12+
{
13+
throw new ArgumentException("Memory pointer should not be zero", nameof(ptr));
14+
}
15+
16+
if (size < 0)
17+
{
18+
throw new ArgumentOutOfRangeException(nameof(size), "Size should be zero or positive.");
19+
}
20+
21+
Ptr = ptr;
22+
Size = size;
23+
_hash = RawMemUtils.FastXorHash(ptr, size);
24+
}
25+
26+
public RawImmutableMemBlock(RawImmutableMemBlock memBlock, IntPtr newPtr)
27+
{
28+
if (memBlock.Ptr == IntPtr.Zero)
29+
{
30+
throw new ArgumentException("Cannot copy non initialized RawImmutableMemBlock structure.", nameof(memBlock));
31+
}
32+
33+
if (newPtr == IntPtr.Zero)
34+
{
35+
throw new ArgumentException("Cannot copy to zero pointer.");
36+
}
37+
38+
RawMemUtils.CopyMemBlocks(memBlock.Ptr, newPtr, memBlock.Size);
39+
Ptr = newPtr;
40+
Size = memBlock.Size;
41+
_hash = memBlock._hash;
42+
}
43+
44+
public IntPtr Ptr { get; }
45+
46+
public int Size { get; }
47+
48+
public bool Equals(RawImmutableMemBlock other)
49+
{
50+
bool preEqual = _hash == other._hash && Size == other.Size;
51+
if (!preEqual)
52+
{
53+
return false;
54+
}
55+
56+
return RawMemUtils.CompareMemBlocks(Ptr, other.Ptr, Size);
57+
}
58+
59+
/// <inheritdoc/>
60+
public override bool Equals(object obj)
61+
{
62+
return obj is RawImmutableMemBlock && Equals((RawImmutableMemBlock)obj);
63+
}
64+
65+
/// <inheritdoc/>
66+
public override int GetHashCode()
67+
{
68+
unchecked
69+
{
70+
return (_hash * 397) ^ Size;
71+
}
72+
}
73+
74+
public static bool operator ==(RawImmutableMemBlock left, RawImmutableMemBlock right)
75+
{
76+
return left.Equals(right);
77+
}
78+
79+
public static bool operator !=(RawImmutableMemBlock left, RawImmutableMemBlock right)
80+
{
81+
return !left.Equals(right);
82+
}
83+
}
84+
}

0 commit comments

Comments
 (0)