Skip to content

Commit

Permalink
0.4: Ported zstd v1.5.0, performance improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
oleg-st committed Jun 27, 2021
1 parent b9b298d commit f57214d
Show file tree
Hide file tree
Showing 76 changed files with 4,026 additions and 1,480 deletions.
20 changes: 17 additions & 3 deletions src/Zstd.Extern/ExternMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Zstd.Extern
{
public class ExternMethods
{
private const string DllName = "libzstd.dll";
private const string DllName = "libzstd";

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ZSTD_createCCtx();
Expand All @@ -14,17 +14,31 @@ public class ExternMethods
public static extern nuint ZSTD_freeCCtx(IntPtr cctx);

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern nuint ZSTD_compressCCtx(IntPtr ctx, IntPtr dst, nuint dstCapacity, IntPtr src, nuint srcSize, int compressionLevel);
public static extern nuint ZSTD_compressCCtx(IntPtr ctx, IntPtr dst, nuint dstCapacity, IntPtr src,
nuint srcSize, int compressionLevel);

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern nuint ZSTD_compress2(IntPtr ctx, IntPtr dst, nuint dstCapacity, IntPtr src, nuint srcSize);

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ZSTD_createDCtx();

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern nuint ZSTD_freeDCtx(IntPtr cctx);

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern nuint ZSTD_decompressDCtx(IntPtr ctx, IntPtr dst, nuint dstCapacity, IntPtr src, nuint srcSize);
public static extern nuint ZSTD_decompressDCtx(IntPtr ctx, IntPtr dst, nuint dstCapacity, IntPtr src,
nuint srcSize);

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern nuint ZSTD_compressBound(nuint srcSize);

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern nuint ZSTD_CCtx_setParameter(IntPtr cctx, ZSTD_cParameter param, int value);

public enum ZSTD_cParameter
{
ZSTD_c_compressionLevel = 100,
}
}
}
Binary file modified src/Zstd.Extern/libzstd.dll
Binary file not shown.
8 changes: 5 additions & 3 deletions src/ZstdSharp.Test/ZstdTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ private Span<byte> CompressNative(byte[] srcBuffer, int compressBound, int level
var cctx = ExternMethods.ZSTD_createCCtx();
try
{
var length = ExternMethods.ZSTD_compressCCtx(cctx,
(IntPtr) bufferPtr, (nuint) buffer.Length,
(IntPtr) srcPtr, (nuint) srcBuffer.Length,
ExternMethods.ZSTD_CCtx_setParameter(cctx, ExternMethods.ZSTD_cParameter.ZSTD_c_compressionLevel,
level);

var length = ExternMethods.ZSTD_compress2(cctx,
(IntPtr) bufferPtr, (nuint) buffer.Length,
(IntPtr) srcPtr, (nuint) srcBuffer.Length);
return new Span<byte>(buffer, 0, (int) length);
}
finally
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#if NETSTANDARD
#if !NETCOREAPP3_0_OR_GREATER

using System.Runtime.CompilerServices;
using static ZstdSharp.UnsafeHelper;
Expand All @@ -16,17 +16,19 @@ namespace System.Numerics
/// The methods use hardware intrinsics when available on the underlying platform,
/// otherwise they use optimized software fallbacks.
/// </summary>
public unsafe static class BitOperations
public static unsafe class BitOperations
{
private static readonly byte* TrailingZeroCountDeBruijn = GetArrayPointer(new byte[]
// hack: should be public because of inline
public static readonly byte* TrailingZeroCountDeBruijn = GetArrayPointer(new byte[]
{
00, 01, 28, 02, 29, 14, 24, 03,
30, 22, 20, 15, 25, 17, 04, 08,
31, 27, 13, 23, 21, 19, 16, 07,
26, 12, 18, 06, 11, 05, 10, 09
});

private static readonly byte* Log2DeBruijn = GetArrayPointer(new byte[]
// hack: should be public because of inline
public static readonly byte* Log2DeBruijn = GetArrayPointer(new byte[]
{
00, 09, 01, 10, 13, 21, 02, 29,
11, 14, 16, 18, 22, 25, 03, 30,
Expand All @@ -40,7 +42,6 @@ public unsafe static class BitOperations
/// </summary>
/// <param name="value">The value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[InlineMethod.Inline]
public static int Log2(uint value)
{
// The 0->0 contract is fulfilled by setting the LSB to 1.
Expand Down Expand Up @@ -77,7 +78,6 @@ public static int Log2(uint value)
/// </summary>
/// <param name="value">The value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[InlineMethod.Inline]
public static int Log2(ulong value)
{
value |= 1;
Expand All @@ -98,7 +98,6 @@ public static int Log2(ulong value)
/// </summary>
/// <param name="value">The value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[InlineMethod.Inline]
public static int TrailingZeroCount(int value)
=> TrailingZeroCount((uint)value);

Expand All @@ -108,7 +107,6 @@ public static int TrailingZeroCount(int value)
/// </summary>
/// <param name="value">The value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[InlineMethod.Inline]
public static int TrailingZeroCount(uint value)
{
// Unguarded fallback contract is 0->0, BSF contract is 0->undefined
Expand All @@ -129,7 +127,6 @@ public static int TrailingZeroCount(uint value)
/// </summary>
/// <param name="value">The value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[InlineMethod.Inline]
public static int TrailingZeroCount(long value)
=> TrailingZeroCount((ulong)value);

Expand All @@ -139,7 +136,6 @@ public static int TrailingZeroCount(long value)
/// </summary>
/// <param name="value">The value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[InlineMethod.Inline]
public static int TrailingZeroCount(ulong value)
{
uint lo = (uint)value;
Expand All @@ -161,7 +157,6 @@ public static int TrailingZeroCount(ulong value)
/// Any value outside the range [0..31] is treated as congruent mod 32.</param>
/// <returns>The rotated value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[InlineMethod.Inline]
public static uint RotateLeft(uint value, int offset)
=> (value << offset) | (value >> (32 - offset));

Expand All @@ -174,7 +169,6 @@ public static uint RotateLeft(uint value, int offset)
/// Any value outside the range [0..63] is treated as congruent mod 64.</param>
/// <returns>The rotated value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[InlineMethod.Inline]
public static ulong RotateLeft(ulong value, int offset)
=> (value << offset) | (value >> (64 - offset));

Expand All @@ -187,7 +181,6 @@ public static ulong RotateLeft(ulong value, int offset)
/// Any value outside the range [0..31] is treated as congruent mod 32.</param>
/// <returns>The rotated value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[InlineMethod.Inline]
public static uint RotateRight(uint value, int offset)
=> (value >> offset) | (value << (32 - offset));

Expand All @@ -200,7 +193,6 @@ public static uint RotateRight(uint value, int offset)
/// Any value outside the range [0..63] is treated as congruent mod 64.</param>
/// <returns>The rotated value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[InlineMethod.Inline]
public static ulong RotateRight(ulong value, int offset)
=> (value >> offset) | (value << (64 - offset));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#if !NET5_0
#if !NET5_0_OR_GREATER
namespace System.Runtime.CompilerServices
{
/// <summary>
Expand All @@ -22,4 +22,4 @@ internal sealed class SkipLocalsInitAttribute : Attribute
{
}
}
#endif
#endif
77 changes: 77 additions & 0 deletions src/ZstdSharp/Polyfills/Unsafe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#if !NETCOREAPP3_0_OR_GREATER

using InlineIL;
using static InlineIL.IL.Emit;

namespace System.Runtime.CompilerServices
{
public static unsafe class Unsafe
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T As<T>(object o)
where T : struct
{
Ldarg(nameof(o));
return IL.Return<T>();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref TTo As<TFrom, TTo>(ref TFrom source)
{
Ldarg(nameof(source));
return ref IL.ReturnRef<TTo>();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int SizeOf<T>()
{
Sizeof(typeof(T));
return IL.Return<int>();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T Add<T>(ref T source, int elementOffset)
{
Ldarg(nameof(source));
Ldarg(nameof(elementOffset));
Sizeof(typeof(T));
Conv_I();
Mul();
IL.Emit.Add();
return ref IL.ReturnRef<T>();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SkipInit<T>(out T value)
{
Ret();
throw IL.Unreachable();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T AsRef<T>(void* source)
{
// For .NET Core the roundtrip via a local is no longer needed
#if NETCOREAPP
IL.Push(source);
return ref IL.ReturnRef<T>();
#else
// Roundtrip via a local to avoid type mismatch on return that the JIT inliner chokes on.
IL.DeclareLocals(
false,
new LocalVar("local", typeof(int).MakeByRefType())
);

IL.Push(source);
Stloc("local");
Ldloc("local");
return ref IL.ReturnRef<T>();
#endif
}
}
}

#endif
54 changes: 54 additions & 0 deletions src/ZstdSharp/Polyfills/Vector128.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#if !NETCOREAPP3_0_OR_GREATER

using System.Runtime.CompilerServices;

namespace System.Runtime.Intrinsics
{
public static class Vector128
{
internal const int Size = 16;

public static unsafe Vector128<byte> Create(byte value)
{
byte* pResult = stackalloc byte[16]
{
value,
value,
value,
value,
value,
value,
value,
value,
value,
value,
value,
value,
value,
value,
value,
value,
};

return Unsafe.AsRef<Vector128<byte>>(pResult);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector128<U> As<T, U>(this Vector128<T> vector)
where T : struct
where U : struct =>
Unsafe.As<Vector128<T>, Vector128<U>>(ref vector);

public static T GetElement<T>(this Vector128<T> vector, int index)
where T : struct
{
ref T e0 = ref Unsafe.As<Vector128<T>, T>(ref vector);
return Unsafe.Add(ref e0, index);
}
}
}

#endif
36 changes: 36 additions & 0 deletions src/ZstdSharp/Polyfills/Vector128_1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#if !NETCOREAPP3_0_OR_GREATER

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Runtime.Intrinsics
{
[StructLayout(LayoutKind.Sequential, Size = Vector128.Size)]
public readonly struct Vector128<T> : IEquatable<Vector128<T>>
where T : struct
{
private readonly ulong _00;
private readonly ulong _01;

public static int Count => Vector128.Size / Unsafe.SizeOf<T>();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Vector128<T> other)
{
for (int i = 0; i < Count; i++)
{
if (!((IEquatable<T>)(this.GetElement(i))).Equals(other.GetElement(i)))
{
return false;
}
}

return true;
}
}
}

#endif
Loading

0 comments on commit f57214d

Please sign in to comment.