diff --git a/.gitignore b/.gitignore
index 94420dc..c5b5bf6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -234,3 +234,7 @@ _Pvt_Extensions
# FAKE - F# Make
.fake/
+/src/DotNetCross.Memory.Copies.Benchmarks2/chart.json
+/I5-4590.xlsx
+/I7-3610QM.xlsx
+/src/DotNetCross.Memory.Copies.Benchmarks2/chart0_8400.json
diff --git a/DotNetCross.Memory.Copies.sln b/DotNetCross.Memory.Copies.sln
index 6472262..b69def4 100644
--- a/DotNetCross.Memory.Copies.sln
+++ b/DotNetCross.Memory.Copies.sln
@@ -1,9 +1,9 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
-VisualStudioVersion = 14.0.24720.0
+VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetCross.Memory.Copies.Benchmarks", "src\DotNetCross.Memory.Copies.Benchmarks\DotNetCross.Memory.Copies.Benchmarks.csproj", "{DF33082A-C7BE-4305-BCAD-159D667C9420}"
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "DotNetCross.Memory.Copies.Benchmarks2", "src\DotNetCross.Memory.Copies.Benchmarks2\DotNetCross.Memory.Copies.Benchmarks2.xproj", "{9396CFEF-F925-4202-98E7-1F0759DF0C5B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -11,10 +11,10 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {DF33082A-C7BE-4305-BCAD-159D667C9420}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {DF33082A-C7BE-4305-BCAD-159D667C9420}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {DF33082A-C7BE-4305-BCAD-159D667C9420}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {DF33082A-C7BE-4305-BCAD-159D667C9420}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9396CFEF-F925-4202-98E7-1F0759DF0C5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9396CFEF-F925-4202-98E7-1F0759DF0C5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9396CFEF-F925-4202-98E7-1F0759DF0C5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9396CFEF-F925-4202-98E7-1F0759DF0C5B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/DotNetCross.Memory.Copies.Benchmarks2.xproj b/src/DotNetCross.Memory.Copies.Benchmarks2/DotNetCross.Memory.Copies.Benchmarks2.xproj
new file mode 100644
index 0000000..93c0858
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/DotNetCross.Memory.Copies.Benchmarks2.xproj
@@ -0,0 +1,19 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+ 9396cfef-f925-4202-98e7-1f0759df0c5b
+ DotNetCross.Memory.Copies.Benchmarks2
+ .\obj
+ .\bin\
+ v4.6.1
+
+
+ 2.0
+
+
+
\ No newline at end of file
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/GoogleChart/C.cs b/src/DotNetCross.Memory.Copies.Benchmarks2/GoogleChart/C.cs
new file mode 100644
index 0000000..c43b042
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/GoogleChart/C.cs
@@ -0,0 +1,8 @@
+namespace DotNetCross.Memory.Copies.Benchmarks2
+{
+ public class C
+ {
+ public object v { get; set; }
+ public string f { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/GoogleChart/Col.cs b/src/DotNetCross.Memory.Copies.Benchmarks2/GoogleChart/Col.cs
new file mode 100644
index 0000000..bb813aa
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/GoogleChart/Col.cs
@@ -0,0 +1,9 @@
+namespace DotNetCross.Memory.Copies.Benchmarks2
+{
+ public class Col
+ {
+ public string id { get; set; }
+ public string label { get; set; }
+ public string type { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/GoogleChart/GoogleChart.cs b/src/DotNetCross.Memory.Copies.Benchmarks2/GoogleChart/GoogleChart.cs
new file mode 100644
index 0000000..707e39c
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/GoogleChart/GoogleChart.cs
@@ -0,0 +1,8 @@
+namespace DotNetCross.Memory.Copies.Benchmarks2
+{
+ public class GoogleChart
+ {
+ public Col[] cols { get; set; }
+ public Row[] rows { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/GoogleChart/Row.cs b/src/DotNetCross.Memory.Copies.Benchmarks2/GoogleChart/Row.cs
new file mode 100644
index 0000000..3c431e8
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/GoogleChart/Row.cs
@@ -0,0 +1,7 @@
+namespace DotNetCross.Memory.Copies.Benchmarks2
+{
+ public class Row
+ {
+ public C[] c { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/Memcopy/AndermanMovsb.cs b/src/DotNetCross.Memory.Copies.Benchmarks2/Memcopy/AndermanMovsb.cs
new file mode 100644
index 0000000..3e586e3
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/Memcopy/AndermanMovsb.cs
@@ -0,0 +1,105 @@
+using System;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+
+namespace DotNetCross.Memory.Copies.Benchmarks2
+{
+ //Used this code only for testing. This code works only on 64bit
+ public static class AndermanMovsb
+ {
+ private const uint PAGE_READWRITE = 0x04;
+ private const uint PAGE_EXECUTE = 0x10;
+ private const uint PAGE_EXECUTE_READWRITE = 0x40;
+ private const uint MEM_COMMIT = 0x1000;
+ private const uint MEM_RELEASE = 0x8000;
+
+ [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, out uint lpflOldProtect);
+
+ [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
+ private static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
+
+ [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);
+
+ public delegate int MyMoveSb(ulong RCX, ulong RDX, ulong R8);
+
+ public static MyMoveSb movsb;
+ public static MyMoveSb pinvoke;
+
+ static AndermanMovsb()
+ {
+ //RAX�=�0000008377040000 RBX�=�0000000000000005 RCX�=�0000000000000004 RDX�=�0000000000000005 RSI�=�0000008300018350 RDI�=�0000000000000004 R8 �=�0000000000000006 R9 �=�000007F9C2460F84 R10�=�0000000000000000 R11�=�0000000000000000 R12�=�00000083754BDF70 R13�=�0000000000000004 R14�=�0000000000000006 R15�=�000000837555A4D0 RIP�=�0000008377040000 RSP�=�00000083754BDDF8 RBP�=�00000083754BDEA0 EFL�=�00000246
+ /*
+ 0: 49 89 fb mov r11,rdi
+ 3: 49 89 f2 mov r10,rsi
+ 6: 48 89 ce mov rsi,rcx
+ 9: 48 89 d7 mov rdi,rdx
+ c: 4c 89 c1 mov rcx,r8
+ f: f3 a4 rep movs BYTE PTR es:[rdi],BYTE PTR ds:[rsi]
+ 11: 4c 89 d6 mov rsi,r10
+ 14: 4c 89 df mov rdi,r11
+ 17: c3 ret
+ */
+ byte[] assemblyCode = { 0x49, 0x89, 0xFB, 0x49, 0x89, 0xF2, 0x48, 0x89, 0xCE, 0x48, 0x89, 0xD7, 0x4C, 0x89, 0xC1, 0xF3, 0xA4, 0x4C, 0x89, 0xD6, 0x4C, 0x89, 0xDF, 0xC3 };
+ byte[] assemblyCode2 = { 0xC3 };
+
+
+ // We need to push the code bytes into a native buffer
+
+ var bufPtr = IntPtr.Zero;
+
+ try
+ {
+ // Put the sourcecode in a native buffer
+ bufPtr = VirtualAlloc(IntPtr.Zero, (IntPtr)4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+
+ Marshal.Copy(assemblyCode, 0, bufPtr, assemblyCode.Length);
+ Marshal.Copy(assemblyCode2, 0, bufPtr+64, assemblyCode2.Length);
+
+ uint oldProtection;
+ var result = VirtualProtect(bufPtr, (IntPtr)assemblyCode.Length, PAGE_EXECUTE, out oldProtection);
+
+ if (!result)
+ {
+ throw new Win32Exception();
+ }
+ movsb = Marshal.GetDelegateForFunctionPointer(bufPtr);
+ pinvoke = Marshal.GetDelegateForFunctionPointer(bufPtr+64);
+ bufPtr = IntPtr.Zero;
+ }
+ finally
+ {
+ // Free the native buffer
+ if (bufPtr != IntPtr.Zero)
+ {
+ var result = VirtualFree(bufPtr, IntPtr.Zero, MEM_RELEASE);
+ if (!result)
+ {
+ throw new Win32Exception();
+ }
+ }
+ }
+ }
+
+
+ public static unsafe void Memmove(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)
+ {
+ if (count == 0) return;
+ if (src == null || dst == null) throw new ArgumentNullException(nameof(src));
+ if (srcOffset + count > src.Length) throw new ArgumentException(nameof(src));
+ if (count < 0 || srcOffset < 0 || dstOffset < 0) throw new ArgumentOutOfRangeException(nameof(count));
+ if (dstOffset + count > dst.Length) throw new ArgumentException(nameof(dst));
+
+ fixed (byte* pSrcOrigin = &src[srcOffset])
+ fixed (byte* pDstOrigin = &dst[dstOffset])
+ {
+ var pSrc = pSrcOrigin;
+ var pDst = pDstOrigin;
+ var result1 = movsb((ulong)pSrc, (ulong)pDst,(ulong)count);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/Memcopy/AndermanOptimized.cs b/src/DotNetCross.Memory.Copies.Benchmarks2/Memcopy/AndermanOptimized.cs
new file mode 100644
index 0000000..2666b07
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/Memcopy/AndermanOptimized.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Diagnostics;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+namespace DotNetCross.Memory.Copies.Benchmarks2
+{
+ public static class AndermanOptimized
+ {
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe void Memmove(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)
+ {
+ const int alignment = 0x10;
+ const int mask = alignment - 1;
+
+ if (count == 0) return;
+ if (src == null || dst == null) throw new ArgumentNullException(nameof(src));
+ if (srcOffset + count > src.Length) throw new ArgumentException(nameof(src));
+ if (count < 0 || srcOffset < 0 || dstOffset < 0) throw new ArgumentOutOfRangeException(nameof(count));
+ if (dstOffset + count > dst.Length) throw new ArgumentException(nameof(dst));
+
+ fixed (byte* pSrcOrigin = &src[srcOffset])
+ fixed (byte* pDstOrigin = &dst[dstOffset])
+ {
+ var pSrc = pSrcOrigin;
+ var pDst = pDstOrigin;
+ if (count < 16)
+ {
+ if (count < 8)
+ {
+ if (count < 4)
+ {
+ if (count < 2)
+ {
+ *(pDst + 0) = *(pSrc + 0);
+ }
+ else
+ {
+ *(short*)pDst = *(short*)pSrc;
+ *(short*)(pDst + (count & 0xf) - 2) = *(short*)(pSrc + (count & 0xf) - 2);
+ }
+ }
+ else
+ {
+ *(int*)pDst = *(int*)pSrc;
+ *(int*)(pDst + (count & 0xf) - 4) = *(int*)(pSrc + (count & 0xf) - 4);
+ }
+
+ }
+ else
+ {
+ *(long*)pDst = *(long*)pSrc;
+ *(long*)(pDst + (count & 0xf) - 8) = *(long*)(pSrc + (count & 0xf) - 8);
+ }
+ return;
+ }
+
+ pSrc -= (long)pDst;
+ Unsafe.Write(pDst, Unsafe.Read>(pSrc + (long)pDst));
+
+ var offset = (int)((ulong)pDst & mask);
+ count += offset - alignment;
+ pDst += alignment - offset;
+
+ while (count >= 4 * Vector.Count)
+ {
+ var x1 = Unsafe.Read>(pSrc + (long)pDst);
+ var x2 = Unsafe.Read>(pSrc + (long)pDst + Vector.Count);
+ count -= 4 * Vector.Count;
+ Unsafe.Write(pDst, x1);
+ Unsafe.Write(pDst + Vector.Count, x2);
+ pDst += 4 * Vector.Count;
+ x1 = Unsafe.Read>(pSrc + (long)pDst - 2 * Vector.Count);
+ x2 = Unsafe.Read>(pSrc + (long)pDst - Vector.Count);
+ Unsafe.Write(pDst - 2 * Vector.Count, x1);
+ Unsafe.Write(pDst - Vector.Count, x2);
+ }
+ while (count >= 2 * Vector.Count)
+ {
+ var x1 = Unsafe.Read>(pSrc + (long)pDst);
+ var x2 = Unsafe.Read>(pSrc + (long)pDst + Vector.Count);
+ count -= 2 * Vector.Count;
+ Unsafe.Write(pDst, x1);
+ Unsafe.Write(pDst + Vector.Count, x2);
+ pDst += 2 * Vector.Count;
+ }
+ while (count >= 1 * Vector.Count)
+ {
+ var x1 = Unsafe.Read>(pSrc + (long)pDst);
+ count -= Vector.Count;
+ Unsafe.Write(pDst, x1);
+ pDst += Vector.Count;
+ }
+ if (count > 0)
+ {
+ pDst += count - Vector.Count;
+ Unsafe.Write(pDst, Unsafe.Read>(pSrc + (long) pDst));
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/Program.cs b/src/DotNetCross.Memory.Copies.Benchmarks2/Program.cs
new file mode 100644
index 0000000..cd2d667
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/Program.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using Newtonsoft.Json;
+
+namespace DotNetCross.Memory.Copies.Benchmarks2
+{
+ public class Program
+ {
+ private const ulong TestDuration = 100;
+ //private static extern bool QueryThreadCycleTime(IntPtr hThread, out ulong cycles);
+ //private static readonly IntPtr PseudoHandle = (IntPtr)(-2);
+ public static double LoopOverhead;
+ public static ulong CyclesPerSecond;
+ public static double NsPerCycle;
+
+ public static void Main(string[] args)
+ {
+ Console.WriteLine($"Warmup...");
+ //Tests.Warmup();
+ CyclesPerSecond = GetCyclesPerSeond();
+ NsPerCycle = 1000*1000*1000.0/CyclesPerSecond;
+ Tests.TestDuration = TestDuration*CyclesPerSecond/1000;
+ LoopOverhead = Tests.TestOverhead(1000,1000);
+
+ Console.WriteLine($"offset src: {Tests.GetOffsetSrc():X04}");
+ Console.WriteLine($"offset dst: {Tests.GetOffsetDst():X04} ");
+ Console.WriteLine($"CyclesPerSecond: {CyclesPerSecond,5:0} ");
+ Console.WriteLine($"nsPerCycle: {NsPerCycle,5:0.0000} ");
+ Console.WriteLine($"loopOverhead: {LoopOverhead,5:0.0000} Cycles");
+ Console.WriteLine($" {LoopOverhead*NsPerCycle,5:0.0000} ns ");
+ Console.WriteLine($"Starting...");
+
+
+ do
+ {
+ var googleChart = new GoogleChart
+ {
+ cols = new[]
+ {
+ new Col {label = "X", type = "number"},
+ new Col {label = "ArrayCopy", type = "number"},
+ new Col {label = "MsvcrtMemmove", type = "number"},
+ new Col {label = "AndermanMovsb", type = "number"},
+ new Col {label = "Anderman", type = "number"}
+ }
+ };
+ var sizes = new[]
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 103, 113, 122, 128, 135,
+ 145,
+ 154, 160, 167, 177, 186, 192, 199, 209, 218, 224, 231, 241, 250, 256, 263, 273, 282, 288, 295, 305, 314, 320, 327, 337, 346, 352, 359, 369, 378, 384, 391, 401, 410, 416, 423, 433, 442, 448, 455, 465, 474, 480, 487, 497, 506, 512, 519, 529, 538, 544, 551, 561, 570, 576, 583,
+ 593, 602, 608, 615, 625, 634, 640, 647, 657, 666, 672, 679, 689, 698, 704, 711, 721, 730, 736, 743, 753, 762, 768, 775, 785, 794, 800, 807, 817, 826, 832, 839, 849, 858, 864, 871, 881, 890, 896, 903, 913, 922, 928, 935, 945, 954, 960, 967, 977, 986, 1024, 1086, 1155, 1223,
+ 1280, 1342, 1411, 1479, 1536, 1598, 1667, 1735, 1792, 1854, 1923, 1991, 2048, 2110, 2179, 2247, 2304, 2366, 2435, 2503, 2560, 2622, 2691, 2759, 2816, 2878, 2947, 3015, 3072, 3134, 3203, 3271, 3328, 3390, 3459, 3527, 3584, 3646, 3715, 3783, 3840, 3902, 3971, 4039, 4096, 4158,
+ 4227, 4295, 4352, 4414, 4483, 4551, 4608, 4670, 4739, 4807, 4864, 4926, 4995, 5063, 5120, 5182, 5251, 5319, 5376, 5438, 5507, 5575, 5632, 5694, 5763, 5831, 5888, 5950, 6019, 6087, 6144, 6206, 6275, 6343, 6400, 6462, 6531, 6599, 6656, 6718, 6787, 6855, 6912, 6974, 7043, 7111,
+ 7168, 7230, 7299, 7367, 7424, 7486, 7555, 7623, 7680, 7742, 7811, 7879, 7936, 7998, 8067, 8135, 8192, 8254, 8323, 8391, 16384, 32768, 65536, 131072, 262144,262144+256,262144+512, 524288, 1048576, 2*1048576, 4*1048576, 8*1048576
+ };
+ var selectedSizes = sizes.Where(x => x >= 0 && x < 10).ToArray();
+ googleChart.rows = new Row[selectedSizes.Count()];
+ var index = 0;
+ foreach (var size in selectedSizes)
+ {
+ var cycles = Tests.TestArray(0, size) - LoopOverhead;
+ var cycles0 = Tests.TestArray(0, size) - LoopOverhead;
+ var cycles2 = Tests.TestMovSb(0, size) - LoopOverhead;
+ var cycles3 = Tests.TestAnderman(0, size) - LoopOverhead;
+ googleChart.rows[index++] = new Row
+ {
+ c = new[]
+ {
+ new C {v = size},
+ new C {v = cycles0},
+ new C {v = cycles2},
+ new C {v = cycles3}
+ }
+ };
+
+ //double cycles3 = TestCode(TestAnderman);
+ Console.WriteLine($"{size:0} {cycles,8:0.00} {cycles2,8:0.00} {cycles3,8:0.00} ");
+ }
+ Console.WriteLine("ready");
+ File.WriteAllText(@"chart.json", "chartData=" + JsonConvert.SerializeObject(googleChart));
+
+ Tests.Warmup();
+ } while (false);
+ }
+
+ private static ulong GetCyclesPerSeond()
+ {
+ var sw = Stopwatch.StartNew();
+ var startms = Rdtsc.TimestampP();
+ do
+ {
+ } while (sw.ElapsedMilliseconds < 1000);
+ var endms = Rdtsc.TimestampP();
+
+ return endms - startms;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/Properties/AssemblyInfo.cs b/src/DotNetCross.Memory.Copies.Benchmarks2/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..2feeb81
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/Properties/AssemblyInfo.cs
@@ -0,0 +1,19 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("test")]
+[assembly: AssemblyTrademark("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("dbae07cb-2303-4f98-953f-f4128a3c9680")]
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/Properties/PublishProfiles/Local-publish.ps1 b/src/DotNetCross.Memory.Copies.Benchmarks2/Properties/PublishProfiles/Local-publish.ps1
new file mode 100644
index 0000000..6d9ff92
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/Properties/PublishProfiles/Local-publish.ps1
@@ -0,0 +1,19 @@
+[cmdletbinding(SupportsShouldProcess=$true)]
+param($publishProperties=@{}, $packOutput, $pubProfilePath)
+
+# to learn more about this file visit https://go.microsoft.com/fwlink/?LinkId=524327
+
+try{
+ if ($publishProperties['ProjectGuid'] -eq $null){
+ $publishProperties['ProjectGuid'] = '9396cfef-f925-4202-98e7-1f0759df0c5b'
+ }
+
+ $publishModulePath = Join-Path (Split-Path $MyInvocation.MyCommand.Path) 'publish-module.psm1'
+ Import-Module $publishModulePath -DisableNameChecking -Force
+
+ # call Publish-AspNet to perform the publish operation
+ Publish-AspNet -publishProperties $publishProperties -packOutput $packOutput -pubProfilePath $pubProfilePath
+}
+catch{
+ "An error occurred during publish.`n{0}" -f $_.Exception.Message | Write-Error
+}
\ No newline at end of file
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/Properties/PublishProfiles/publish-module.psm1 b/src/DotNetCross.Memory.Copies.Benchmarks2/Properties/PublishProfiles/publish-module.psm1
new file mode 100644
index 0000000..adc6ada
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/Properties/PublishProfiles/publish-module.psm1
@@ -0,0 +1,1231 @@
+# WARNING: DO NOT MODIFY this file. Visual Studio will override it.
+param()
+
+$script:AspNetPublishHandlers = @{}
+
+<#
+These settings can be overridden with environment variables.
+The name of the environment variable should use "Publish" as a
+prefix and the names below. For example:
+
+ $env:PublishMSDeployUseChecksum = $true
+#>
+$global:AspNetPublishSettings = New-Object -TypeName PSCustomObject @{
+ MsdeployDefaultProperties = @{
+ 'MSDeployUseChecksum'=$false
+ 'SkipExtraFilesOnServer'=$true
+ 'retryAttempts' = 20
+ 'EnableMSDeployBackup' = $false
+ 'DeleteExistingFiles' = $false
+ 'AllowUntrustedCertificate'= $false
+ 'MSDeployPackageContentFoldername'='website\'
+ 'EnvironmentName' = 'Production'
+ 'AuthType'='Basic'
+ 'MSDeployPublishMethod'='WMSVC'
+ }
+}
+
+function InternalOverrideSettingsFromEnv{
+ [cmdletbinding()]
+ param(
+ [Parameter(Position=0)]
+ [object[]]$settings = ($global:AspNetPublishSettings,$global:AspNetPublishSettings.MsdeployDefaultProperties),
+
+ [Parameter(Position=1)]
+ [string]$prefix = 'Publish'
+ )
+ process{
+ foreach($settingsObj in $settings){
+ if($settingsObj -eq $null){
+ continue
+ }
+
+ $settingNames = $null
+ if($settingsObj -is [hashtable]){
+ $settingNames = $settingsObj.Keys
+ }
+ else{
+ $settingNames = ($settingsObj | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name)
+
+ }
+
+ foreach($name in @($settingNames)){
+ $fullname = ('{0}{1}' -f $prefix,$name)
+ if(Test-Path "env:$fullname"){
+ $settingsObj.$name = ((get-childitem "env:$fullname").Value)
+ }
+ }
+ }
+ }
+}
+
+InternalOverrideSettingsFromEnv -prefix 'Publish' -settings $global:AspNetPublishSettings,$global:AspNetPublishSettings.MsdeployDefaultProperties
+
+function Register-AspnetPublishHandler{
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory=$true,Position=0)]
+ $name,
+ [Parameter(Mandatory=$true,Position=1)]
+ [ScriptBlock]$handler,
+ [switch]$force
+ )
+ process{
+ if(!($script:AspNetPublishHandlers[$name]) -or $force ){
+ 'Adding handler for [{0}]' -f $name | Write-Verbose
+ $script:AspNetPublishHandlers[$name] = $handler
+ }
+ elseif(!($force)){
+ 'Ignoring call to Register-AspnetPublishHandler for [name={0}], because a handler with that name exists and -force was not passed.' -f $name | Write-Verbose
+ }
+ }
+}
+
+function Get-AspnetPublishHandler{
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory=$true,Position=0)]
+ $name
+ )
+ process{
+ $foundHandler = $script:AspNetPublishHandlers[$name]
+
+ if(!$foundHandler){
+ throw ('AspnetPublishHandler with name "{0}" was not found' -f $name)
+ }
+
+ $foundHandler
+ }
+}
+
+function GetInternal-ExcludeFilesArg{
+ [cmdletbinding()]
+ param(
+ $publishProperties
+ )
+ process{
+ $excludeFiles = $publishProperties['ExcludeFiles']
+ foreach($exclude in $excludeFiles){
+ if($exclude){
+ [string]$objName = $exclude['objectname']
+
+ if([string]::IsNullOrEmpty($objName)){
+ $objName = 'filePath'
+ }
+
+ $excludePath = $exclude['absolutepath']
+
+ # output the result to the return list
+ ('-skip:objectName={0},absolutePath=''{1}''' -f $objName, $excludePath)
+ }
+ }
+ }
+}
+
+function GetInternal-ReplacementsMSDeployArgs{
+ [cmdletbinding()]
+ param(
+ $publishProperties
+ )
+ process{
+ foreach($replace in ($publishProperties['Replacements'])){
+ if($replace){
+ $typeValue = $replace['type']
+ if(!$typeValue){ $typeValue = 'TextFile' }
+
+ $file = $replace['file']
+ $match = $replace['match']
+ $newValue = $replace['newValue']
+
+ if($file -and $match -and $newValue){
+ $setParam = ('-setParam:type={0},scope={1},match={2},value={3}' -f $typeValue,$file, $match,$newValue)
+ 'Adding setparam [{0}]' -f $setParam | Write-Verbose
+
+ # return it
+ $setParam
+ }
+ else{
+ 'Skipping replacement because its missing a required value.[file="{0}",match="{1}",newValue="{2}"]' -f $file,$match,$newValue | Write-Verbose
+ }
+ }
+ }
+ }
+}
+
+<#
+.SYNOPSIS
+Returns an array of msdeploy arguments that are used across different providers.
+For example this will handle useChecksum, AppOffline etc.
+This will also add default properties if they are missing.
+#>
+function GetInternal-SharedMSDeployParametersFrom{
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory=$true,Position=0)]
+ [HashTable]$publishProperties,
+ [Parameter(Mandatory=$true,Position=1)]
+ [System.IO.FileInfo]$packOutput
+ )
+ process{
+ $sharedArgs = New-Object psobject -Property @{
+ ExtraArgs = @()
+ DestFragment = ''
+ EFMigrationData = @{}
+ }
+
+ # add default properties if they are missing
+ foreach($propName in $global:AspNetPublishSettings.MsdeployDefaultProperties.Keys){
+ if($publishProperties["$propName"] -eq $null){
+ $defValue = $global:AspNetPublishSettings.MsdeployDefaultProperties["$propName"]
+ 'Adding default property to publishProperties ["{0}"="{1}"]' -f $propName,$defValue | Write-Verbose
+ $publishProperties["$propName"] = $defValue
+ }
+ }
+
+ if($publishProperties['MSDeployUseChecksum'] -eq $true){
+ $sharedArgs.ExtraArgs += '-usechecksum'
+ }
+
+ if($publishProperties['EnableMSDeployAppOffline'] -eq $true){
+ $sharedArgs.ExtraArgs += '-enablerule:AppOffline'
+ }
+
+ if($publishProperties['WebPublishMethod'] -eq 'MSDeploy'){
+ if($publishProperties['SkipExtraFilesOnServer'] -eq $true){
+ $sharedArgs.ExtraArgs += '-enableRule:DoNotDeleteRule'
+ }
+ }
+
+ if($publishProperties['WebPublishMethod'] -eq 'FileSystem'){
+ if($publishProperties['DeleteExistingFiles'] -eq $false){
+ $sharedArgs.ExtraArgs += '-enableRule:DoNotDeleteRule'
+ }
+ }
+
+ if($publishProperties['retryAttempts']){
+ $sharedArgs.ExtraArgs += ('-retryAttempts:{0}' -f ([int]$publishProperties['retryAttempts']))
+ }
+
+ if($publishProperties['EncryptWebConfig'] -eq $true){
+ $sharedArgs.ExtraArgs += '-EnableRule:EncryptWebConfig'
+ }
+
+ if($publishProperties['EnableMSDeployBackup'] -eq $false){
+ $sharedArgs.ExtraArgs += '-disablerule:BackupRule'
+ }
+
+ if($publishProperties['AllowUntrustedCertificate'] -eq $true){
+ $sharedArgs.ExtraArgs += '-allowUntrusted'
+ }
+
+ # add excludes
+ $sharedArgs.ExtraArgs += (GetInternal-ExcludeFilesArg -publishProperties $publishProperties)
+ # add replacements
+ $sharedArgs.ExtraArgs += (GetInternal-ReplacementsMSDeployArgs -publishProperties $publishProperties)
+
+ # add EF Migration
+ if (($publishProperties['EfMigrations'] -ne $null) -and $publishProperties['EfMigrations'].Count -gt 0){
+ if (!(Test-Path -Path $publishProperties['ProjectPath'])) {
+ throw 'ProjectPath property needs to be defined in the pubxml for EF migration.'
+ }
+ try {
+ # generate T-SQL files
+ $EFSqlFiles = GenerateInternal-EFMigrationScripts -projectPath $publishProperties['ProjectPath'] -packOutput $packOutput -EFMigrations $publishProperties['EfMigrations']
+ $sharedArgs.EFMigrationData.Add('EFSqlFiles',$EFSqlFiles)
+ }
+ catch {
+ throw ('An error occurred while generating EF migrations. {0} {1}' -f $_.Exception,(Get-PSCallStack))
+ }
+ }
+ # add connection string update
+ if (($publishProperties['DestinationConnectionStrings'] -ne $null) -and $publishProperties['DestinationConnectionStrings'].Count -gt 0) {
+ try {
+ # create/update appsettings.[environment].json
+ GenerateInternal-AppSettingsFile -packOutput $packOutput -environmentName $publishProperties['EnvironmentName'] -connectionStrings $publishProperties['DestinationConnectionStrings']
+ }
+ catch {
+ throw ('An error occurred while generating the publish appsettings file. {0} {1}' -f $_.Exception,(Get-PSCallStack))
+ }
+ }
+
+ if(-not [string]::IsNullOrWhiteSpace($publishProperties['ProjectGuid'])) {
+ AddInternal-ProjectGuidToWebConfig -publishProperties $publishProperties -packOutput $packOutput
+ }
+
+ # return the args
+ $sharedArgs
+ }
+}
+
+<#
+.SYNOPSIS
+This will publish the folder based on the properties in $publishProperties
+
+.PARAMETER publishProperties
+This is a hashtable containing the publish properties. See the examples here for more info on how to use this parameter.
+
+.PARAMETER packOutput
+The folder path to the output of the dnu publish command. This folder contains the files
+that will be published.
+
+.PARAMETER pubProfilePath
+Path to a publish profile (.pubxml file) to import publish properties from. If the same property exists in
+publishProperties and the publish profile then publishProperties will win.
+
+.EXAMPLE
+ Publish-AspNet -packOutput $packOutput -publishProperties @{
+ 'WebPublishMethod'='MSDeploy'
+ 'MSDeployServiceURL'='contoso.scm.azurewebsites.net:443';`
+ 'DeployIisAppPath'='contoso';'Username'='$contoso';'Password'="$env:PublishPwd"}
+
+.EXAMPLE
+Publish-AspNet -packOutput $packOutput -publishProperties @{
+ 'WebPublishMethod'='FileSystem'
+ 'publishUrl'="$publishDest"
+ }
+
+.EXAMPLE
+Publish-AspNet -packOutput $packOutput -publishProperties @{
+ 'WebPublishMethod'='MSDeploy'
+ 'MSDeployServiceURL'='contoso.scm.azurewebsites.net:443';`
+'DeployIisAppPath'='contoso';'Username'='$contoso';'Password'="$env:PublishPwd"
+ 'ExcludeFiles'=@(
+ @{'absolutepath'='test.txt'},
+ @{'absolutepath'='references.js'}
+)}
+
+.EXAMPLE
+Publish-AspNet -packOutput $packOutput -publishProperties @{
+ 'WebPublishMethod'='FileSystem'
+ 'publishUrl'="$publishDest"
+ 'ExcludeFiles'=@(
+ @{'absolutepath'='test.txt'},
+ @{'absolutepath'='_references.js'})
+ 'Replacements' = @(
+ @{'file'='test.txt$';'match'='REPLACEME';'newValue'='updatedValue'})
+ }
+
+Publish-AspNet -packOutput $packOutput -publishProperties @{
+ 'WebPublishMethod'='FileSystem'
+ 'publishUrl'="$publishDest"
+ 'ExcludeFiles'=@(
+ @{'absolutepath'='test.txt'},
+ @{'absolutepath'='c:\\full\\path\\ok\\as\\well\\_references.js'})
+ 'Replacements' = @(
+ @{'file'='test.txt$';'match'='REPLACEME';'newValue'='updatedValue'})
+ }
+
+.EXAMPLE
+Publish-AspNet -packOutput $packOutput -publishProperties @{
+ 'WebPublishMethod'='FileSystem'
+ 'publishUrl'="$publishDest"
+ 'EnableMSDeployAppOffline'='true'
+ 'AppOfflineTemplate'='offline-template.html'
+ 'MSDeployUseChecksum'='true'
+}
+#>
+function Publish-AspNet{
+ param(
+ [Parameter(Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
+ [hashtable]$publishProperties = @{},
+
+ [Parameter(Mandatory = $true,Position=1,ValueFromPipelineByPropertyName=$true)]
+ [System.IO.FileInfo]$packOutput,
+
+ [Parameter(Position=2,ValueFromPipelineByPropertyName=$true)]
+ [System.IO.FileInfo]$pubProfilePath
+ )
+ process{
+ if($publishProperties['WebPublishMethodOverride']){
+ 'Overriding publish method from $publishProperties[''WebPublishMethodOverride''] to [{0}]' -f ($publishProperties['WebPublishMethodOverride']) | Write-Verbose
+ $publishProperties['WebPublishMethod'] = $publishProperties['WebPublishMethodOverride']
+ }
+
+ if(-not [string]::IsNullOrWhiteSpace($pubProfilePath)){
+ $profileProperties = Get-PropertiesFromPublishProfile -filepath $pubProfilePath
+ foreach($key in $profileProperties.Keys){
+ if(-not ($publishProperties.ContainsKey($key))){
+ 'Adding properties from publish profile [''{0}''=''{1}'']' -f $key,$profileProperties[$key] | Write-Verbose
+ $publishProperties.Add($key,$profileProperties[$key])
+ }
+ }
+ }
+
+ if(!([System.IO.Path]::IsPathRooted($packOutput))){
+ $packOutput = [System.IO.Path]::GetFullPath((Join-Path $pwd $packOutput))
+ }
+
+ $pubMethod = $publishProperties['WebPublishMethod']
+ 'Publishing with publish method [{0}]' -f $pubMethod | Write-Output
+
+ # get the handler based on WebPublishMethod, and call it.
+ &(Get-AspnetPublishHandler -name $pubMethod) $publishProperties $packOutput
+ }
+}
+
+<#
+.SYNOPSIS
+
+Inputs:
+
+Example of $xmlDocument: ''
+Example of $providerDataArray:
+
+ [System.Collections.ArrayList]$providerDataArray = @()
+
+ $iisAppSourceKeyValue=@{"iisApp" = @{"path"='c:\temp\pathtofiles';"appOfflineTemplate" ='offline-template.html'}}
+ $providerDataArray.Add($iisAppSourceKeyValue)
+
+ $dbfullsqlKeyValue=@{"dbfullsql" = @{"path"="c:\Temp\PathToSqlFile"}}
+ $providerDataArray.Add($dbfullsqlKeyValue)
+
+ $dbfullsqlKeyValue=@{"dbfullsql" = @{"path"="c:\Temp\PathToSqlFile2"}}
+ $providerDataArray.Add($dbfullsqlKeyValue)
+
+ Manifest File content:
+
+
+
+
+
+
+#>
+function AddInternal-ProviderDataToManifest {
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory=$true, Position=0)]
+ [XML]$xmlDocument,
+ [Parameter(Position=1)]
+ [System.Collections.ArrayList]$providerDataArray
+ )
+ process {
+ $siteNode = $xmlDocument.SelectSingleNode("/sitemanifest")
+ if ($siteNode -eq $null) {
+ throw 'sitemanifest element is missing in the xml object'
+ }
+ foreach ($providerData in $providerDataArray) {
+ foreach ($providerName in $providerData.Keys) {
+ $providerValue = $providerData[$providerName]
+ $xmlNode = $xmlDocument.CreateElement($providerName)
+ foreach ($providerValueKey in $providerValue.Keys) {
+ $xmlNode.SetAttribute($providerValueKey, $providerValue[$providerValueKey]) | Out-Null
+ }
+ $siteNode.AppendChild($xmlNode) | Out-Null
+ }
+ }
+ }
+}
+
+function AddInternal-ProjectGuidToWebConfig {
+ [cmdletbinding()]
+ param(
+ [Parameter(Position=0)]
+ [HashTable]$publishProperties,
+ [Parameter(Position=1)]
+ [System.IO.FileInfo]$packOutput
+ )
+ process {
+ try {
+ [Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq") | Out-Null
+ $webConfigPath = Join-Path $packOutput 'web.config'
+ $projectGuidCommentValue = 'ProjectGuid: {0}' -f $publishProperties['ProjectGuid']
+ $xDoc = [System.Xml.Linq.XDocument]::Load($webConfigPath)
+ $allNodes = $xDoc.DescendantNodes()
+ $projectGuidComment = $allNodes | Where-Object { $_.NodeType -eq [System.Xml.XmlNodeType]::Comment -and $_.Value -eq $projectGuidCommentValue } | Select -First 1
+ if($projectGuidComment -ne $null) {
+ if($publishProperties['IgnoreProjectGuid'] -eq $true) {
+ $projectGuidComment.Remove() | Out-Null
+ $xDoc.Save($webConfigPath) | Out-Null
+ }
+ }
+ else {
+ if(-not ($publishProperties['IgnoreProjectGuid'] -eq $true)) {
+ $projectGuidComment = New-Object -TypeName System.Xml.Linq.XComment -ArgumentList $projectGuidCommentValue
+ $xDoc.LastNode.AddAfterSelf($projectGuidComment) | Out-Null
+ $xDoc.Save($webConfigPath) | Out-Null
+ }
+ }
+ }
+ catch {
+ }
+ }
+}
+
+<#
+.SYNOPSIS
+
+Example of $EFMigrations:
+ $EFMigrations = @{'CarContext'='Car Context ConnectionString';'MovieContext'='Movie Context Connection String'}
+
+#>
+
+function GenerateInternal-EFMigrationScripts {
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory=$true,Position=0)]
+ [System.IO.FileInfo]$projectPath,
+ [Parameter(Mandatory=$true,Position=1)]
+ [System.IO.FileInfo]$packOutput,
+ [Parameter(Position=2)]
+ [HashTable]$EFMigrations
+ )
+ process {
+ $files = @{}
+ $dotnetExePath = GetInternal-DotNetExePath
+ foreach ($dbContextName in $EFMigrations.Keys) {
+ try
+ {
+ $tempDir = GetInternal-PublishTempPath -packOutput $packOutput
+ $efScriptFile = Join-Path $tempDir ('{0}.sql' -f $dbContextName)
+ $arg = ('ef migrations script --idempotent --output {0} --context {1}' -f
+ $efScriptFile,
+ $dbContextName)
+
+ Execute-Command $dotnetExePath $arg $projectPath | Out-Null
+ if (Test-Path -Path $efScriptFile) {
+ if (!($files.ContainsKey($dbContextName))) {
+ $files.Add($dbContextName, $efScriptFile) | Out-Null
+ }
+ }
+ }
+ catch
+ {
+ throw 'error occured when executing dotnet.exe to generate EF T-SQL file'
+ }
+ }
+ # return files object
+ $files
+ }
+}
+
+<#
+.SYNOPSIS
+
+Example of $connectionStrings:
+ $connectionStrings = @{'DefaultConnection'='Default ConnectionString';'CarConnection'='Car Connection String'}
+
+#>
+function GenerateInternal-AppSettingsFile {
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory = $true,Position=0)]
+ [System.IO.FileInfo]$packOutput,
+ [Parameter(Mandatory = $true,Position=1)]
+ [string]$environmentName,
+ [Parameter(Position=2)]
+ [HashTable]$connectionStrings
+ )
+ process {
+ $configProdJsonFile = 'appsettings.{0}.json' -f $environmentName
+ $configProdJsonFilePath = Join-Path -Path $packOutput -ChildPath $configProdJsonFile
+
+ if ([string]::IsNullOrEmpty($configProdJsonFilePath)) {
+ throw ('The path of {0} is empty' -f $configProdJsonFilePath)
+ }
+
+ if(!(Test-Path -Path $configProdJsonFilePath)) {
+ # create new file
+ '{}' | out-file -encoding utf8 -filePath $configProdJsonFilePath -Force
+ }
+
+ $jsonObj = ConvertFrom-Json -InputObject (Get-Content -Path $configProdJsonFilePath -Raw)
+ # update when there exists one or more connection strings
+ if ($connectionStrings -ne $null) {
+ foreach ($name in $connectionStrings.Keys) {
+ #check for hierarchy style
+ if ($jsonObj.ConnectionStrings.$name) {
+ $jsonObj.ConnectionStrings.$name = $connectionStrings[$name]
+ continue
+ }
+ #check for horizontal style
+ $horizontalName = 'ConnectionStrings.{0}:' -f $name
+ if ($jsonObj.$horizontalName) {
+ $jsonObj.$horizontalName = $connectionStrings[$name]
+ continue
+ }
+ # create new one
+ if (!($jsonObj.ConnectionStrings)) {
+ $contentForDefaultConnection = '{}'
+ $jsonObj | Add-Member -name 'ConnectionStrings' -value (ConvertFrom-Json -InputObject $contentForDefaultConnection) -MemberType NoteProperty | Out-Null
+ }
+ if (!($jsonObj.ConnectionStrings.$name)) {
+ $jsonObj.ConnectionStrings | Add-Member -name $name -value $connectionStrings[$name] -MemberType NoteProperty | Out-Null
+ }
+ }
+ }
+
+ $jsonObj | ConvertTo-Json | out-file -encoding utf8 -filePath $configProdJsonFilePath -Force
+
+ #return the path of config.[environment].json
+ $configProdJsonFilePath
+ }
+}
+
+<#
+.SYNOPSIS
+
+Inputs:
+Example of $providerDataArray:
+
+ [System.Collections.ArrayList]$providerDataArray = @()
+
+ $iisAppSourceKeyValue=@{"iisApp" = @{"path"='c:\temp\pathtofiles';"appOfflineTemplate" ='offline-template.html'}}
+ $providerDataArray.Add($iisAppSourceKeyValue)
+
+ $dbfullsqlKeyValue=@{"dbfullsql" = @{"path"="c:\Temp\PathToSqlFile"}}
+ $providerDataArray.Add($dbfullsqlKeyValue)
+
+ $dbfullsqlKeyValue=@{"dbfullsql" = @{"path"="c:\Temp\PathToSqlFile2"}}
+ $providerDataArray.Add($dbfullsqlKeyValue)
+
+ Manifest File content:
+
+
+
+
+
+
+
+#>
+
+function GenerateInternal-ManifestFile {
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory=$true,Position=0)]
+ [System.IO.FileInfo]$packOutput,
+ [Parameter(Mandatory=$true,Position=1)]
+ $publishProperties,
+ [Parameter(Mandatory=$true,Position=2)]
+ [System.Collections.ArrayList]$providerDataArray,
+ [Parameter(Mandatory=$true,Position=3)]
+ [ValidateNotNull()]
+ $manifestFileName
+ )
+ process{
+ $xmlDocument = [xml]''
+ AddInternal-ProviderDataToManifest -xmlDocument $xmlDocument -providerDataArray $providerDataArray | Out-Null
+ $publishTempDir = GetInternal-PublishTempPath -packOutput $packOutput
+ $XMLFile = Join-Path $publishTempDir $manifestFileName
+ $xmlDocument.OuterXml | out-file -encoding utf8 -filePath $XMLFile -Force
+
+ # return
+ [System.IO.FileInfo]$XMLFile
+ }
+}
+
+function GetInternal-PublishTempPath {
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory=$true, Position=0)]
+ [System.IO.FileInfo]$packOutput
+ )
+ process {
+ $tempDir = [io.path]::GetTempPath()
+ $packOutputFolderName = Split-Path $packOutput -Leaf
+ $publishTempDir = [io.path]::combine($tempDir,'PublishTemp','obj',$packOutputFolderName)
+ if (!(Test-Path -Path $publishTempDir)) {
+ New-Item -Path $publishTempDir -type directory | Out-Null
+ }
+ # return
+ [System.IO.FileInfo]$publishTempDir
+ }
+}
+
+function Publish-AspNetMSDeploy{
+ param(
+ [Parameter(Mandatory = $true,Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
+ $publishProperties,
+ [Parameter(Mandatory = $true,Position=1,ValueFromPipelineByPropertyName=$true)]
+ $packOutput
+ )
+ process{
+ if($publishProperties){
+ $publishPwd = $publishProperties['Password']
+
+ $sharedArgs = GetInternal-SharedMSDeployParametersFrom -publishProperties $publishProperties -packOutput $packOutput
+ $iisAppPath = $publishProperties['DeployIisAppPath']
+
+ # create source manifest
+
+ # e.g
+ #
+ #
+ #
+ #
+ #
+ #
+
+ [System.Collections.ArrayList]$providerDataArray = @()
+ $iisAppValues = @{"path"=$packOutput};
+ $iisAppSourceKeyValue=@{"iisApp" = $iisAppValues}
+ $providerDataArray.Add($iisAppSourceKeyValue) | Out-Null
+
+ if ($sharedArgs.EFMigrationData -ne $null -and $sharedArgs.EFMigrationData.Contains('EFSqlFiles')) {
+ foreach ($sqlFile in $sharedArgs.EFMigrationData['EFSqlFiles'].Values) {
+ $dbFullSqlSourceKeyValue=@{"dbFullSql" = @{"path"=$sqlFile}}
+ $providerDataArray.Add($dbFullSqlSourceKeyValue) | Out-Null
+ }
+ }
+
+ [System.IO.FileInfo]$sourceXMLFile = GenerateInternal-ManifestFile -packOutput $packOutput -publishProperties $publishProperties -providerDataArray $providerDataArray -manifestFileName 'SourceManifest.xml'
+
+ $providerDataArray.Clear() | Out-Null
+ # create destination manifest
+
+ # e.g
+ #
+ #
+ #
+ #
+ #
+
+ $iisAppValues = @{"path"=$iisAppPath};
+ if(-not [string]::IsNullOrWhiteSpace($publishProperties['AppOfflineTemplate'])){
+ $iisAppValues.Add("appOfflineTemplate", $publishProperties['AppOfflineTemplate']) | Out-Null
+ }
+
+ $iisAppDestinationKeyValue=@{"iisApp" = $iisAppValues}
+ $providerDataArray.Add($iisAppDestinationKeyValue) | Out-Null
+
+ if ($publishProperties['EfMigrations'] -ne $null -and $publishProperties['EfMigrations'].Count -gt 0) {
+ foreach ($connectionString in $publishProperties['EfMigrations'].Values) {
+ $dbFullSqlDestinationKeyValue=@{"dbFullSql" = @{"path"=$connectionString}}
+ $providerDataArray.Add($dbFullSqlDestinationKeyValue) | Out-Null
+ }
+ }
+
+
+ [System.IO.FileInfo]$destXMLFile = GenerateInternal-ManifestFile -packOutput $packOutput -publishProperties $publishProperties -providerDataArray $providerDataArray -manifestFileName 'DestinationManifest.xml'
+
+ <#
+ "C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe"
+ -source:manifest='C:\Users\testuser\AppData\Local\Temp\PublishTemp\obj\SourceManifest.xml'
+ -dest:manifest='C:\Users\testuser\AppData\Local\Temp\PublishTemp\obj\DestManifest.xml',ComputerName='https://contoso.scm.azurewebsites.net/msdeploy.axd',UserName='$contoso',Password='',IncludeAcls='False',AuthType='Basic'
+ -verb:sync
+ -enableRule:DoNotDeleteRule
+ -retryAttempts=2"
+ #>
+
+ if(-not [string]::IsNullOrWhiteSpace($publishProperties['MSDeployPublishMethod'])){
+ $serviceMethod = $publishProperties['MSDeployPublishMethod']
+ }
+
+ $msdeployComputerName= InternalNormalize-MSDeployUrl -serviceUrl $publishProperties['MSDeployServiceURL'] -siteName $iisAppPath -serviceMethod $publishProperties['MSDeployPublishMethod']
+ if($publishProperties['UseMSDeployServiceURLAsIs'] -eq $true){
+ $msdeployComputerName = $publishProperties['MSDeployServiceURL']
+ }
+
+ $publishArgs = @()
+ #use manifest to publish
+ $publishArgs += ('-source:manifest=''{0}''' -f $sourceXMLFile.FullName)
+ $publishArgs += ('-dest:manifest=''{0}'',ComputerName=''{1}'',UserName=''{2}'',Password=''{3}'',IncludeAcls=''False'',AuthType=''{4}''{5}' -f
+ $destXMLFile.FullName,
+ $msdeployComputerName,
+ $publishProperties['UserName'],
+ $publishPwd,
+ $publishProperties['AuthType'],
+ $sharedArgs.DestFragment)
+ $publishArgs += '-verb:sync'
+ $publishArgs += $sharedArgs.ExtraArgs
+
+ $command = '"{0}" {1}' -f (Get-MSDeploy),($publishArgs -join ' ')
+
+ if (! [String]::IsNullOrEmpty($publishPwd)) {
+ $command.Replace($publishPwd,'{PASSWORD-REMOVED-FROM-LOG}') | Print-CommandString
+ }
+ Execute-Command -exePath (Get-MSDeploy) -arguments ($publishArgs -join ' ')
+ }
+ else{
+ throw 'publishProperties is empty, cannot publish'
+ }
+ }
+}
+
+function Escape-TextForRegularExpressions{
+ [cmdletbinding()]
+ param(
+ [Parameter(Position=0,Mandatory=$true)]
+ [string]$text
+ )
+ process{
+ [regex]::Escape($text)
+ }
+}
+
+function Publish-AspNetMSDeployPackage{
+ param(
+ [Parameter(Mandatory = $true,Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
+ $publishProperties,
+ [Parameter(Mandatory = $true,Position=1,ValueFromPipelineByPropertyName=$true)]
+ $packOutput
+ )
+ process{
+ if($publishProperties){
+ $packageDestinationFilepath = $publishProperties['DesktopBuildPackageLocation']
+
+ if(!$packageDestinationFilepath){
+ throw ('The package destination property (DesktopBuildPackageLocation) was not found in the publish properties')
+ }
+
+ if(!([System.IO.Path]::IsPathRooted($packageDestinationFilepath))){
+ $packageDestinationFilepath = [System.IO.Path]::GetFullPath((Join-Path $pwd $packageDestinationFilepath))
+ }
+
+ # if the dir doesn't exist create it
+ $pkgDir = ((new-object -typename System.IO.FileInfo($packageDestinationFilepath)).Directory)
+ if(!(Test-Path -Path $pkgDir)) {
+ New-Item $pkgDir -type Directory | Out-Null
+ }
+
+ <#
+ "C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe"
+ -source:manifest='C:\Users\testuser\AppData\Local\Temp\PublishTemp\obj\SourceManifest.xml'
+ -dest:package=c:\temp\path\contosoweb.zip
+ -verb:sync
+ -enableRule:DoNotDeleteRule
+ -retryAttempts=2
+ #>
+
+ $sharedArgs = GetInternal-SharedMSDeployParametersFrom -publishProperties $publishProperties -packOutput $packOutput
+
+ # create source manifest
+
+ # e.g
+ #
+ #
+ #
+ #
+
+ [System.Collections.ArrayList]$providerDataArray = @()
+ $iisAppSourceKeyValue=@{"iisApp" = @{"path"=$packOutput}}
+ $providerDataArray.Add($iisAppSourceKeyValue) | Out-Null
+
+ [System.IO.FileInfo]$sourceXMLFile = GenerateInternal-ManifestFile -packOutput $packOutput -publishProperties $publishProperties -providerDataArray $providerDataArray -manifestFileName 'SourceManifest.xml'
+
+ $publishArgs = @()
+ $publishArgs += ('-source:manifest=''{0}''' -f $sourceXMLFile.FullName)
+ $publishArgs += ('-dest:package=''{0}''' -f $packageDestinationFilepath)
+ $publishArgs += '-verb:sync'
+ $packageContentFolder = $publishProperties['MSDeployPackageContentFoldername']
+ if(!$packageContentFolder){ $packageContentFolder = 'website' }
+ $publishArgs += ('-replace:match=''{0}'',replace=''{1}''' -f (Escape-TextForRegularExpressions $packOutput), $packageContentFolder )
+ $publishArgs += $sharedArgs.ExtraArgs
+
+ $command = '"{0}" {1}' -f (Get-MSDeploy),($publishArgs -join ' ')
+ $command | Print-CommandString
+ Execute-Command -exePath (Get-MSDeploy) -arguments ($publishArgs -join ' ')
+ }
+ else{
+ throw 'publishProperties is empty, cannot publish'
+ }
+ }
+}
+
+function Publish-AspNetFileSystem{
+ param(
+ [Parameter(Mandatory = $true,Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
+ $publishProperties,
+ [Parameter(Mandatory = $true,Position=1,ValueFromPipelineByPropertyName=$true)]
+ $packOutput
+ )
+ process{
+ $pubOut = $publishProperties['publishUrl']
+
+ if([string]::IsNullOrWhiteSpace($pubOut)){
+ throw ('publishUrl is a required property for FileSystem publish but it was empty.')
+ }
+
+ # if it's a relative path then update it to a full path
+ if(!([System.IO.Path]::IsPathRooted($pubOut))){
+ $pubOut = [System.IO.Path]::GetFullPath((Join-Path $pwd $pubOut))
+ $publishProperties['publishUrl'] = "$pubOut"
+ }
+
+ 'Publishing files to {0}' -f $pubOut | Write-Output
+
+ # we use msdeploy.exe because it supports incremental publish/skips/replacements/etc
+ # msdeploy.exe -verb:sync -source:manifest='C:\Users\testuser\AppData\Local\Temp\PublishTemp\obj\SourceManifest.xml' -dest:manifest='C:\Users\testuser\AppData\Local\Temp\PublishTemp\obj\DestManifest.xml'
+
+ $sharedArgs = GetInternal-SharedMSDeployParametersFrom -publishProperties $publishProperties -packOutput $packOutput
+
+ # create source manifest
+
+ # e.g
+ #
+ #
+ #
+ #
+
+ [System.Collections.ArrayList]$providerDataArray = @()
+ $contentPathValues = @{"path"=$packOutput};
+ $contentPathSourceKeyValue=@{"contentPath" = $contentPathValues}
+ $providerDataArray.Add($contentPathSourceKeyValue) | Out-Null
+
+ [System.IO.FileInfo]$sourceXMLFile = GenerateInternal-ManifestFile -packOutput $packOutput -publishProperties $publishProperties -providerDataArray $providerDataArray -manifestFileName 'SourceManifest.xml'
+
+ $providerDataArray.Clear() | Out-Null
+ # create destination manifest
+
+ # e.g
+ #
+ #
+ #
+ $contentPathValues = @{"path"=$publishProperties['publishUrl']};
+ if(-not [string]::IsNullOrWhiteSpace($publishProperties['AppOfflineTemplate'])){
+ $contentPathValues.Add("appOfflineTemplate", $publishProperties['AppOfflineTemplate']) | Out-Null
+ }
+ $contentPathDestinationKeyValue=@{"contentPath" = $contentPathValues}
+ $providerDataArray.Add($contentPathDestinationKeyValue) | Out-Null
+
+ [System.IO.FileInfo]$destXMLFile = GenerateInternal-ManifestFile -packOutput $packOutput -publishProperties $publishProperties -providerDataArray $providerDataArray -manifestFileName 'DestinationManifest.xml'
+
+ $publishArgs = @()
+ $publishArgs += ('-source:manifest=''{0}''' -f $sourceXMLFile.FullName)
+ $publishArgs += ('-dest:manifest=''{0}''{1}' -f $destXMLFile.FullName, $sharedArgs.DestFragment)
+ $publishArgs += '-verb:sync'
+ $publishArgs += $sharedArgs.ExtraArgs
+
+ $command = '"{0}" {1}' -f (Get-MSDeploy),($publishArgs -join ' ')
+ $command | Print-CommandString
+ Execute-Command -exePath (Get-MSDeploy) -arguments ($publishArgs -join ' ')
+
+ # copy sql script to script folder
+ if (($sharedArgs.EFMigrationData['EFSqlFiles'] -ne $null) -and ($sharedArgs.EFMigrationData['EFSqlFiles'].Count -gt 0)) {
+ $scriptsDir = Join-Path $pubOut 'efscripts'
+
+ if (!(Test-Path -Path $scriptsDir)) {
+ New-Item -Path $scriptsDir -type directory | Out-Null
+ }
+
+ foreach ($sqlFile in $sharedArgs.EFMigrationData['EFSqlFiles'].Values) {
+ Copy-Item $sqlFile -Destination $scriptsDir -Force -Recurse | Out-Null
+ }
+ }
+ }
+}
+
+<#
+.SYNOPSIS
+ This can be used to read a publish profile to extract the property values into a hashtable.
+
+.PARAMETER filepath
+ Path to the publish profile to get the properties from. Currenlty this only supports reading
+ .pubxml files.
+
+.EXAMPLE
+ Get-PropertiesFromPublishProfile -filepath c:\projects\publish\devpublish.pubxml
+#>
+function Get-PropertiesFromPublishProfile{
+ [cmdletbinding()]
+ param(
+ [Parameter(Position=0,Mandatory=$true)]
+ [ValidateNotNull()]
+ [ValidateScript({Test-Path $_})]
+ [System.IO.FileInfo]$filepath
+ )
+ begin{
+ Add-Type -AssemblyName System.Core
+ Add-Type -AssemblyName Microsoft.Build
+ }
+ process{
+ 'Reading publish properties from profile [{0}]' -f $filepath | Write-Verbose
+ # use MSBuild to get the project and read properties
+ $projectCollection = (New-Object Microsoft.Build.Evaluation.ProjectCollection)
+ if(!([System.IO.Path]::IsPathRooted($filepath))){
+ $filepath = [System.IO.Path]::GetFullPath((Join-Path $pwd $filepath))
+ }
+ $project = ([Microsoft.Build.Construction.ProjectRootElement]::Open([string]$filepath.Fullname, $projectCollection))
+
+ $properties = @{}
+ foreach($property in $project.Properties){
+ $properties[$property.Name]=$property.Value
+ }
+
+ $properties
+ }
+}
+
+function Print-CommandString{
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true)]
+ $command
+ )
+ process{
+ 'Executing command [{0}]' -f $command | Write-Output
+ }
+}
+
+function Execute-CommandString{
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true)]
+ [string[]]$command,
+
+ [switch]
+ $useInvokeExpression,
+
+ [switch]
+ $ignoreErrors
+ )
+ process{
+ foreach($cmdToExec in $command){
+ 'Executing command [{0}]' -f $cmdToExec | Write-Verbose
+ if($useInvokeExpression){
+ try {
+ Invoke-Expression -Command $cmdToExec
+ }
+ catch {
+ if(-not $ignoreErrors){
+ $msg = ('The command [{0}] exited with exception [{1}]' -f $cmdToExec, $_.ToString())
+ throw $msg
+ }
+ }
+ }
+ else {
+ cmd.exe /D /C $cmdToExec
+
+ if(-not $ignoreErrors -and ($LASTEXITCODE -ne 0)){
+ $msg = ('The command [{0}] exited with code [{1}]' -f $cmdToExec, $LASTEXITCODE)
+ throw $msg
+ }
+ }
+ }
+ }
+}
+
+function Execute-Command {
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory = $true,Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
+ [String]$exePath,
+ [Parameter(Mandatory = $true,Position=1,ValueFromPipelineByPropertyName=$true)]
+ [String]$arguments,
+ [Parameter(Position=2)]
+ [System.IO.FileInfo]$workingDirectory
+ )
+ process{
+ $psi = New-Object -TypeName System.Diagnostics.ProcessStartInfo
+ $psi.CreateNoWindow = $true
+ $psi.UseShellExecute = $false
+ $psi.RedirectStandardOutput = $true
+ $psi.RedirectStandardError=$true
+ $psi.FileName = $exePath
+ $psi.Arguments = $arguments
+ if($workingDirectory -and (Test-Path -Path $workingDirectory)) {
+ $psi.WorkingDirectory = $workingDirectory
+ }
+
+ $process = New-Object -TypeName System.Diagnostics.Process
+ $process.StartInfo = $psi
+ $process.EnableRaisingEvents=$true
+
+ # Register the event handler for error
+ $stdErrEvent = Register-ObjectEvent -InputObject $process -EventName 'ErrorDataReceived' -Action {
+ if (! [String]::IsNullOrEmpty($EventArgs.Data)) {
+ $EventArgs.Data | Write-Error
+ }
+ }
+
+ # Starting process.
+ $process.Start() | Out-Null
+ $process.BeginErrorReadLine() | Out-Null
+ $output = $process.StandardOutput.ReadToEnd()
+ $process.WaitForExit() | Out-Null
+ $output | Write-Output
+
+ # UnRegister the event handler for error
+ Unregister-Event -SourceIdentifier $stdErrEvent.Name | Out-Null
+ }
+}
+
+
+function GetInternal-DotNetExePath {
+ process {
+ $dotnetinstallpath = $env:dotnetinstallpath
+ if (!$dotnetinstallpath) {
+ $DotNetRegItem = Get-ItemProperty -Path 'hklm:\software\dotnet\setup\'
+ if ($env:DOTNET_HOME) {
+ $dotnetinstallpath = Join-Path $env:DOTNET_HOME -ChildPath 'dotnet.exe'
+ }
+ elseif ($DotNetRegItem -and $DotNetRegItem.InstallDir){
+ $dotnetinstallpath = Join-Path $DotNetRegItem.InstallDir -ChildPath 'dotnet.exe'
+ }
+ }
+ if (!(Test-Path $dotnetinstallpath)) {
+ throw 'Unable to find dotnet.exe, please install it and try again'
+ }
+ # return
+ [System.IO.FileInfo]$dotnetinstallpath
+ }
+}
+
+function Get-MSDeploy{
+ [cmdletbinding()]
+ param()
+ process{
+ $installPath = $env:msdeployinstallpath
+
+ if(!$installPath){
+ $keysToCheck = @('hklm:\SOFTWARE\Microsoft\IIS Extensions\MSDeploy\3','hklm:\SOFTWARE\Microsoft\IIS Extensions\MSDeploy\2','hklm:\SOFTWARE\Microsoft\IIS Extensions\MSDeploy\1')
+
+ foreach($keyToCheck in $keysToCheck){
+ if(Test-Path $keyToCheck){
+ $installPath = (Get-itemproperty $keyToCheck -Name InstallPath -ErrorAction SilentlyContinue | select -ExpandProperty InstallPath -ErrorAction SilentlyContinue)
+ }
+
+ if($installPath){
+ break;
+ }
+ }
+ }
+
+ if(!$installPath){
+ throw "Unable to find msdeploy.exe, please install it and try again"
+ }
+
+ [string]$msdInstallLoc = (join-path $installPath 'msdeploy.exe')
+
+ "Found msdeploy.exe at [{0}]" -f $msdInstallLoc | Write-Verbose
+
+ $msdInstallLoc
+ }
+}
+
+function InternalNormalize-MSDeployUrl{
+ [cmdletbinding()]
+ param(
+ [Parameter(Position=0,Mandatory=$true)]
+ [string]$serviceUrl,
+
+ [string] $siteName,
+
+ [ValidateSet('WMSVC','RemoteAgent','InProc')]
+ [string]$serviceMethod = 'WMSVC'
+ )
+ process{
+ $tempUrl = $serviceUrl
+ $resultUrl = $serviceUrl
+
+ $httpsStr = 'https://'
+ $httpStr = 'http://'
+ $msdeployAxd = 'msdeploy.axd'
+
+ if(-not [string]::IsNullOrWhiteSpace($serviceUrl)){
+ if([string]::Compare($serviceMethod,'WMSVC',[StringComparison]::OrdinalIgnoreCase) -eq 0){
+ # if no http or https then add one
+ if(-not ($serviceUrl.StartsWith($httpStr,[StringComparison]::OrdinalIgnoreCase) -or
+ $serviceUrl.StartsWith($httpsStr,[StringComparison]::OrdinalIgnoreCase)) ){
+
+ $serviceUrl = [string]::Concat($httpsStr,$serviceUrl.TrimStart())
+ }
+ [System.Uri]$serviceUri = New-Object -TypeName 'System.Uri' $serviceUrl
+ [System.UriBuilder]$serviceUriBuilder = New-Object -TypeName 'System.UriBuilder' $serviceUrl
+
+ # if it's https and the port was not passed in override it to 8172
+ if( ([string]::Compare('https',$serviceUriBuilder.Scheme,[StringComparison]::OrdinalIgnoreCase) -eq 0) -and
+ -not $serviceUrl.Contains((':{0}' -f $serviceUriBuilder.Port)) ) {
+ $serviceUriBuilder.Port = 8172
+ }
+
+ # if no path then add one
+ if([string]::Compare('/',$serviceUriBuilder.Path,[StringComparison]::OrdinalIgnoreCase) -eq 0){
+ $serviceUriBuilder.Path = $msdeployAxd
+ }
+
+ if ([string]::IsNullOrEmpty($serviceUriBuilder.Query) -and -not([string]::IsNullOrEmpty($siteName)))
+ {
+ $serviceUriBuilder.Query = "site=" + $siteName;
+ }
+
+ $resultUrl = $serviceUriBuilder.Uri.AbsoluteUri
+ }
+ elseif([string]::Compare($serviceMethod,'RemoteAgent',[StringComparison]::OrdinalIgnoreCase) -eq 0){
+ [System.UriBuilder]$serviceUriBuilder = New-Object -TypeName 'System.UriBuilder' $serviceUrl
+ # http://{computername}/MSDEPLOYAGENTSERVICE
+ # remote agent must use http
+ $serviceUriBuilder.Scheme = 'http'
+ $serviceUriBuilder.Path = '/MSDEPLOYAGENTSERVICE'
+
+ $resultUrl = $serviceUriBuilder.Uri.AbsoluteUri
+ }
+ else{
+ # see if it's for localhost
+ [System.Uri]$serviceUri = New-Object -TypeName 'System.Uri' $serviceUrl
+ $resultUrl = $serviceUri.AbsoluteUri
+ }
+ }
+
+ # return the result to the caller
+ $resultUrl
+ }
+}
+
+function InternalRegister-AspNetKnownPublishHandlers{
+ [cmdletbinding()]
+ param()
+ process{
+ 'Registering MSDeploy handler' | Write-Verbose
+ Register-AspnetPublishHandler -name 'MSDeploy' -force -handler {
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory = $true,Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
+ $publishProperties,
+ [Parameter(Mandatory = $true,Position=1,ValueFromPipelineByPropertyName=$true)]
+ $packOutput
+ )
+
+ Publish-AspNetMSDeploy -publishProperties $publishProperties -packOutput $packOutput
+ }
+
+ 'Registering MSDeploy package handler' | Write-Verbose
+ Register-AspnetPublishHandler -name 'Package' -force -handler {
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory = $true,Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
+ $publishProperties,
+ [Parameter(Mandatory = $true,Position=1,ValueFromPipelineByPropertyName=$true)]
+ $packOutput
+ )
+
+ Publish-AspNetMSDeployPackage -publishProperties $publishProperties -packOutput $packOutput
+ }
+
+ 'Registering FileSystem handler' | Write-Verbose
+ Register-AspnetPublishHandler -name 'FileSystem' -force -handler {
+ [cmdletbinding()]
+ param(
+ [Parameter(Mandatory = $true,Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
+ $publishProperties,
+ [Parameter(Mandatory = $true,Position=1,ValueFromPipelineByPropertyName=$true)]
+ $packOutput
+ )
+
+ Publish-AspNetFileSystem -publishProperties $publishProperties -packOutput $packOutput
+ }
+ }
+}
+
+<#
+.SYNOPSIS
+ Used for testing purposes only.
+#>
+function InternalReset-AspNetPublishHandlers{
+ [cmdletbinding()]
+ param()
+ process{
+ $script:AspNetPublishHandlers = @{}
+ InternalRegister-AspNetKnownPublishHandlers
+ }
+}
+
+Export-ModuleMember -function Get-*,Publish-*,Register-*,Enable-*
+if($env:IsDeveloperMachine){
+ # you can set the env var to expose all functions to importer. easy for development.
+ # this is required for executing pester test cases, it's set by build.ps1
+ Export-ModuleMember -function *
+}
+
+# register the handlers so that Publish-AspNet can be called
+InternalRegister-AspNetKnownPublishHandlers
+
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/Rdtsc.cs b/src/DotNetCross.Memory.Copies.Benchmarks2/Rdtsc.cs
new file mode 100644
index 0000000..42aeac9
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/Rdtsc.cs
@@ -0,0 +1,287 @@
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace DotNetCross.Memory.Copies.Benchmarks2
+{
+ public static class Rdtsc
+ {
+ [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+ public delegate ulong FuncUInt64();
+
+ private const uint PAGE_READWRITE = 0x04;
+ private const uint PAGE_EXECUTE = 0x10;
+ private const uint PAGE_EXECUTE_READWRITE = 0x40;
+ private const uint MEM_COMMIT = 0x1000;
+ private const uint MEM_RELEASE = 0x8000;
+
+ ///
+ /// Uses rdtsc. On non-Intel uses Stopwatch.GetTimestamp.
+ ///
+ public static readonly FuncUInt64 Timestamp;
+
+ ///
+ /// Uses rdtscp if present. Otherwise uses cpuid + rdtsc. On
+ /// non-Intel uses Stopwatch.GetTimestamp.
+ ///
+ public static readonly FuncUInt64 TimestampP;
+
+ public static readonly bool IsRdtscSupported;
+ public static readonly bool IsRdtscPSupported;
+
+ static Rdtsc()
+ {
+ SystemInfo systemInfo;
+ GetNativeSystemInfo(out systemInfo);
+
+ if (systemInfo.wProcessorArchitecture != 0 /* PROCESSOR_ARCHITECTURE_INTEL */&&
+ systemInfo.wProcessorArchitecture != 9 /* PROCESSOR_ARCHITECTURE_AMD64 */)
+ {
+ // Fallback for ARM/IA64/...
+ Timestamp = StopwatchGetTimestamp;
+ TimestampP = StopwatchGetTimestamp;
+ IsRdtscSupported = false;
+ IsRdtscPSupported = false;
+ return;
+ }
+
+ byte[] cpuid, rdtsc, rdtscp, rdtsccpuid, dummy;
+
+ IsRdtscSupported = true;
+
+ // Assembly generated with https://defuse.ca/online-x86-assembler.htm
+
+ /* CPUID x64:
+ push rbx;
+ mov eax, 0x80000000;
+ cpuid;
+ mov ebx, 0x80000001;
+ cmp eax, ebx;
+ jb Error;
+ mov eax, ebx;
+ cpuid;
+ mov eax, ecx;
+ shl rax, 0x20;
+ or rax, rdx
+ jmp End;
+ Error:
+ xor rax, rax;
+ End:
+ pop rbx;
+ ret;
+
+ 0: 53 push rbx
+ 1: b8 00 00 00 80 mov eax,0x80000000
+ 6: 0f a2 cpuid
+ 8: bb 01 00 00 80 mov ebx,0x80000001
+ d: 39 d8 cmp eax,ebx
+ f: 72 0f jb 20
+ 11: 89 d8 mov eax,ebx
+ 13: 0f a2 cpuid
+ 15: 89 c8 mov eax,ecx
+ 17: 48 c1 e0 20 shl rax,0x20
+ 1b: 48 09 d0 or rax,rdx
+ 1e: eb 03 jmp 23
+ 0000000000000020 :
+ 20: 48 31 c0 xor rax,rax
+ 0000000000000023 :
+ 23: 5b pop rbx
+ 24: c3 ret
+ */
+ cpuid = new byte[] { 0x53, 0xB8, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xA2, 0xBB, 0x01, 0x00, 0x00, 0x80, 0x39, 0xD8, 0x72, 0x16, 0x89, 0xD8, 0x48, 0xC7, 0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xA2, 0x89, 0xC8, 0x48, 0xC1, 0xE0, 0x20, 0x48, 0x09, 0xD0, 0xEB, 0x03, 0x48, 0x31, 0xC0, 0x5B, 0xC3 };
+
+ /* RDTSC x64:
+ rdtsc;
+ shl rdx, 0x20;
+ or rax,rdx;
+ ret;
+
+ 0: 0f 31 rdtsc
+ 2: 48 c1 e2 20 shl rdx,0x20
+ 6: 48 09 d0 or rax,rdx
+ 9: c3 ret
+ */
+ rdtsc = new byte[] { 0x0F, 0x31, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0xC3 };
+
+ /* RDTSCP x64
+ rdtscp;
+ shl rdx, 0x20;
+ or rax, rdx;
+ ret;
+
+ 0: 0f 01 f9 rdtscp
+ 3: 48 c1 e2 20 shl rdx,0x20
+ 7: 48 09 d0 or rax,rdx
+ a: c3 ret
+ */
+ rdtscp = new byte[] { 0x0F, 0x01, 0xF9, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0xC3 };
+
+ /* RDTSC + CPUID x64
+ push rbx;
+ xor eax, eax;
+ cpuid;
+ rdtsc;
+ shl rdx, 0x20;
+ or rax, rdx;
+ pop rbx;
+ ret;
+
+ 0: 53 push rbx
+ 1: 31 c0 xor eax,eax
+ 3: 0f a2 cpuid
+ 5: 0f 31 rdtsc
+ 7: 48 c1 e2 20 shl rdx,0x20
+ b: 48 09 d0 or rax,rdx
+ e: 5b pop rbx
+ f: c3 ret
+ */
+ rdtsccpuid = new byte[] { 0x53, 0x31, 0xC0, 0x0F, 0xA2, 0x0F, 0x31, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0x5B, 0xC3 };
+ dummy = new byte[] {0xC3};
+
+ var buf = IntPtr.Zero;
+
+ try
+ {
+ // We pad the functions to 64 bytes (the length of a cache
+ // line on the Intel processors)
+ var cpuidLength = (cpuid.Length & 63) != 0 ? (cpuid.Length | 63) + 1 : cpuid.Length;
+ var rdtscLength = (rdtsc.Length & 63) != 0 ? (rdtsc.Length | 63) + 1 : rdtsc.Length;
+ var rdtscpLength = (rdtscp.Length & 63) != 0 ? (rdtscp.Length | 63) + 1 : rdtscp.Length;
+ var rdtsccpuidLength = (rdtsccpuid.Length & 63) != 0 ? (rdtsccpuid.Length | 63) + 1 : rdtsccpuid.Length;
+ var dummyLength = (dummy.Length & 63) != 0 ? (dummy.Length | 63) + 1 : dummy.Length;
+
+ // We don't know which one of rdtscp or rdtsccpuid we will
+ // use, so we calculate space for the biggest one.
+ // Note that it is very unlikely that we will go over 4096
+ // bytes (the minimum size of memory allocated by
+ // VirtualAlloc)
+ var totalLength = cpuidLength + rdtscLength + Math.Max(rdtscpLength, rdtsccpuidLength)+dummyLength;
+
+ // We VirtualAlloc totalLength bytes, with R/W access
+ // Note that from what I've read, MEM_RESERVE is useless
+ // if the first parameter is IntPtr.Zero
+ buf = VirtualAlloc(IntPtr.Zero, (IntPtr)totalLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+
+ if (buf == IntPtr.Zero)
+ {
+ throw new Win32Exception();
+ }
+
+ // Copy cpuid instructions in the buf
+ Marshal.Copy(cpuid, 0, buf, cpuid.Length);
+
+ for (var i = cpuid.Length; i < cpuidLength; i++)
+ {
+ Marshal.WriteByte(buf, i, 0x90); // nop
+ }
+
+ // Copy rdtsc instructions in the buf
+ Marshal.Copy(rdtsc, 0, buf + cpuidLength, rdtsc.Length);
+
+ for (var i = rdtsc.Length; i < rdtscLength; i++)
+ {
+ Marshal.WriteByte(buf, cpuidLength + i, 0x90); // nop
+ }
+ var cpuidFunc = Marshal.GetDelegateForFunctionPointer(buf);
+
+ // We use cpuid, EAX=0x80000001 to check for the rdtscp
+ var supportedFeatures = cpuidFunc();
+
+ byte[] rdtscpSelected;
+ int rdtscpSelectedLength;
+
+ // Check the rdtscp flag
+ if ((supportedFeatures & (1L << 27)) != 0)
+ {
+ // rdtscp supported
+ rdtscpSelected = rdtscp;
+ rdtscpSelectedLength = rdtscpLength;
+ IsRdtscPSupported = true;
+ }
+ else
+ {
+ // rdtscp not supported. We use cpuid + rdtsc
+ rdtscpSelected = rdtsccpuid;
+ rdtscpSelectedLength = rdtsccpuidLength;
+ IsRdtscPSupported = false;
+ }
+
+ // Copy rdtscp/rdtsccpuid instructions in the buf
+ Marshal.Copy(rdtscpSelected, 0, buf + cpuidLength + rdtscLength, rdtscpSelected.Length);
+
+ for (var i = rdtscpSelected.Length; i < rdtscpSelectedLength; i++)
+ {
+ Marshal.WriteByte(buf, cpuidLength + rdtscLength + i, 0x90); // nop
+ }
+
+
+ // Change the access of the allocated memory from R/W to Execute
+ uint oldProtection;
+ var result = VirtualProtect(buf, (IntPtr)totalLength, PAGE_EXECUTE, out oldProtection);
+
+ if (!result)
+ {
+ throw new Win32Exception();
+ }
+
+ // Create a delegate to the "function"
+ Timestamp = Marshal.GetDelegateForFunctionPointer(buf + cpuidLength);
+ TimestampP = Marshal.GetDelegateForFunctionPointer(buf + cpuidLength + rdtscLength);
+ buf = IntPtr.Zero;
+ }
+ finally
+ {
+ // There was an error!
+ if (buf != IntPtr.Zero)
+ {
+ // Free the allocated memory
+ var result = VirtualFree(buf, IntPtr.Zero, MEM_RELEASE);
+
+ if (!result)
+ {
+ throw new Win32Exception();
+ }
+ }
+ }
+ }
+
+
+ [DllImport("kernel32.dll", ExactSpelling = true)]
+ private static extern void GetNativeSystemInfo(out SystemInfo lpSystemInfo);
+
+ [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
+ private static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
+
+ [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, out uint lpflOldProtect);
+
+ [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);
+
+ // Fallback if rdtsc isn't available. We can't use directly
+ // Stopwatch.GetTimestamp() because the return type is different.
+ private static ulong StopwatchGetTimestamp()
+ {
+ return unchecked((ulong)Stopwatch.GetTimestamp());
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct SystemInfo
+ {
+ public readonly ushort wProcessorArchitecture;
+ public readonly ushort wReserved;
+ public readonly uint dwPageSize;
+ public readonly IntPtr lpMinimumApplicationAddress;
+ public readonly IntPtr lpMaximumApplicationAddress;
+ public readonly IntPtr dwActiveProcessorMask;
+ public readonly uint dwNumberOfProcessors;
+ public readonly uint dwProcessorType;
+ public readonly uint dwAllocationGranularity;
+ public readonly ushort wProcessorLevel;
+ public readonly ushort wProcessorRevision;
+ }
+ }
+}
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/Tests.cs b/src/DotNetCross.Memory.Copies.Benchmarks2/Tests.cs
new file mode 100644
index 0000000..6105df1
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/Tests.cs
@@ -0,0 +1,193 @@
+using System;
+
+namespace DotNetCross.Memory.Copies.Benchmarks2
+{
+ public static class Tests
+ {
+ private const int BufferSize = 1024*1024*1024;
+ private static readonly byte[] _src = new byte[BufferSize];
+ private static readonly byte[] _dst = new byte[BufferSize];
+
+ private const int Cached = 0; //Pseudo Random Test
+ private const int Randomizor = +0x3313751; //Pseudo Random Test
+ private const int Alignment = 1; //Alignment test
+ private const int Sequence = -1; //read seq through array
+ private const int TestMode = Randomizor; //Alignment test
+
+ private const int MinIterations = 50;
+ public static ulong TestDuration = 1000000;
+
+ public static unsafe int GetOffsetDst()
+ {
+ fixed (byte* pSrcOrigin = &_dst[0])
+ {
+ return 0x10 - (int) ((ulong) pSrcOrigin & 0xF);
+ }
+ }
+
+ public static unsafe int GetOffsetSrc()
+ {
+ fixed (byte* pSrcOrigin = &_src[0])
+ {
+ return 0x10 - (int) ((ulong) pSrcOrigin & 0xF);
+ }
+ }
+
+ public static void Warmup()
+ {
+ for (var i = 1; i < 256; i++)
+ {
+ _src[i] = (byte) i;
+ _dst[i] = 0;
+ }
+ for (var size = 0; size < 32768; size++)
+ {
+ AndermanOptimized.Memmove(_src, 0, _dst, 0, size);
+ for (var j = 0; j < size + 0; j++)
+ {
+ if (_src[j] != _dst[j])
+ throw new Exception($"i={size}, j={j} _src[j]({_src[j]}) != _dst[j]({_dst[j]})");
+ _dst[j] = 0;
+ }
+ }
+ }
+
+ public static double TestOverhead(int offset, int size)
+ {
+ var mincycles = ulong.MaxValue;
+ var startTest = Rdtsc.TimestampP();
+ var testCycles = 0UL;
+
+ do
+ {
+ ulong cycles = 0;
+ for (var j = 1; j < 1000; j++)
+ {
+ var start = Rdtsc.TimestampP();
+ for (var h = 1; h < MinIterations; h++)
+ {
+ offset += TestMode == -1 ? size : TestMode;
+ if (offset + size >= BufferSize) offset &= 0xFFfff;
+ }
+ var end = Rdtsc.TimestampP();
+ cycles += end - start;
+ }
+
+ if (cycles < mincycles) mincycles = cycles;
+
+ testCycles = Rdtsc.TimestampP() - startTest;
+ } while (testCycles < TestDuration && testCycles > 0);
+ return offset >= 0 ? mincycles/1000.0/MinIterations : 0;
+ }
+
+ public static double TestAnderman(int offset, int size)
+ {
+ var mincycles = ulong.MaxValue;
+ var startTest = Rdtsc.TimestampP();
+ var testCycles = 0UL;
+
+ do
+ {
+ var start = Rdtsc.TimestampP();
+ for (var j = 1; j < MinIterations; j++)
+ {
+ offset += TestMode == -1 ? size : TestMode;
+ if (offset + size >= BufferSize) offset &= 0xFFfff;
+ AndermanOptimized.Memmove(_src, offset, _dst, offset, size);
+ }
+ var end = Rdtsc.TimestampP();
+ var cycles = end - start;
+ if (cycles <= mincycles)
+ {
+ mincycles = cycles;
+ }
+ testCycles = Rdtsc.TimestampP() - startTest;
+ } while (testCycles < TestDuration && testCycles > 0);
+ return mincycles/(double) MinIterations;
+ }
+
+ public static double TestArray(int offset, int size)
+ {
+ var mincycles = ulong.MaxValue;
+ var startTest = Rdtsc.TimestampP();
+ var testCycles = 0UL;
+
+ do
+ {
+ var start = Rdtsc.TimestampP();
+ for (var j = 1; j < MinIterations; j++)
+ {
+ offset += TestMode == -1 ? size : TestMode;
+ if (offset + size >= BufferSize) offset &= 0xFFfff;
+ Array.Copy(_src, offset, _dst, offset, size);
+ }
+ var end = Rdtsc.TimestampP();
+ var cycles = end - start;
+ if (cycles <= mincycles)
+ {
+ mincycles = cycles;
+ }
+ testCycles = Rdtsc.TimestampP() - startTest;
+ } while (testCycles < TestDuration && testCycles > 0);
+ return mincycles/(double) MinIterations;
+ }
+
+ public static double TestMovSb(int offset, int size)
+ {
+ var mincycles = ulong.MaxValue;
+ var startTest = Rdtsc.TimestampP();
+ var testCycles = 0UL;
+
+ do
+ {
+ var start = Rdtsc.TimestampP();
+ for (var j = 1; j < MinIterations; j++)
+ {
+ offset += TestMode == -1 ? size : TestMode;
+ if (offset + size >= BufferSize) offset &= 0xFFfff;
+ AndermanMovsb.Memmove(_src, offset, _dst, offset, size);
+ }
+ var end = Rdtsc.TimestampP();
+ var cycles = end - start;
+ if (cycles <= mincycles)
+ {
+ mincycles = cycles;
+ }
+ testCycles = Rdtsc.TimestampP() - startTest;
+ } while (testCycles < TestDuration && testCycles > 0);
+ return mincycles/(double) MinIterations;
+ }
+
+ public static double TestDelegate(Func copyAction, int offset, int size)
+ {
+ var mincycles = ulong.MaxValue;
+ var startTest = Rdtsc.TimestampP();
+ var testCycles = 0UL;
+
+ do
+ {
+ var cycles = copyAction(offset, offset, size);
+ if (cycles <= mincycles)
+ {
+ mincycles = cycles;
+ }
+ testCycles = Rdtsc.TimestampP() - startTest;
+ } while (testCycles < TestDuration && testCycles > 0);
+
+ return mincycles/(double) MinIterations;
+ }
+
+ public static ulong TestAndermanDelegate(int offset, int size)
+ {
+ var start = Rdtsc.TimestampP();
+ for (var j = 1; j < MinIterations; j++)
+ {
+ offset += TestMode == -1 ? size : TestMode;
+ if (offset + size >= BufferSize) offset &= 0xFFfff;
+ AndermanOptimized.Memmove(_src, offset, _dst, offset, size);
+ }
+ var end = Rdtsc.TimestampP();
+ return end - start;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/chart.html b/src/DotNetCross.Memory.Copies.Benchmarks2/chart.html
new file mode 100644
index 0000000..697521b
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/chart.html
@@ -0,0 +1,36 @@
+
+
+
+ chart
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks2/project.json b/src/DotNetCross.Memory.Copies.Benchmarks2/project.json
new file mode 100644
index 0000000..259edb9
--- /dev/null
+++ b/src/DotNetCross.Memory.Copies.Benchmarks2/project.json
@@ -0,0 +1,27 @@
+{
+ "version": "1.0.0-*",
+ "buildOptions": {
+ "emitEntryPoint": true,
+ "optimize": true,
+ "allowUnsafe": true
+ },
+ "dependencies": {
+ "Microsoft.NETCore.App": {
+ "type": "platform",
+ "version": "1.0.1"
+ },
+ "System.Runtime.CompilerServices.Unsafe": "4.0.0",
+ "System.Linq": "4.1.0",
+ "System.Reflection": "4.1.0",
+ "Newtonsoft.Json": "9.0.1"
+ },
+ "runtimes": {
+ "win8-x64": {}
+ },
+ "frameworks": {
+ "netcoreapp1.0": {
+ "dependencies": {
+ }
+ }
+ }
+}
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/Anderman.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/Anderman.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/Anderman.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/Anderman.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/App.config b/src/old/DotNetCross.Memory.Copies.Benchmarks/App.config
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/App.config
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/App.config
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/CopiesBenchmark.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/CopiesBenchmark.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/CopiesBenchmark.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/CopiesBenchmark.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/DotNetCross.Memory.Copies.Benchmarks.csproj b/src/old/DotNetCross.Memory.Copies.Benchmarks/DotNetCross.Memory.Copies.Benchmarks.csproj
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/DotNetCross.Memory.Copies.Benchmarks.csproj
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/DotNetCross.Memory.Copies.Benchmarks.csproj
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/Illyriad.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/Illyriad.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/Illyriad.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/Illyriad.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/Msvcrt.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/Msvcrt.cs
similarity index 72%
rename from src/DotNetCross.Memory.Copies.Benchmarks/Msvcrt.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/Msvcrt.cs
index 615176a..c548286 100644
--- a/src/DotNetCross.Memory.Copies.Benchmarks/Msvcrt.cs
+++ b/src/old/DotNetCross.Memory.Copies.Benchmarks/Msvcrt.cs
@@ -12,17 +12,14 @@ public static unsafe void Memmove(byte[] src, int srcOffset, byte[] dst, int dst
if (srcOffset + count > src.Length) throw new ArgumentException(nameof(src));
if (dstOffset + count > dst.Length) throw new ArgumentException(nameof(dst));
- fixed (byte* srcOrigin = src)
- fixed (byte* dstOrigin = dst)
+ fixed (byte* pSrcOrigin = &src[srcOffset])
+ fixed (byte* pDstOrigin = &dst[dstOffset])
{
- var pSrc = srcOrigin + srcOffset;
- var pDst = dstOrigin + dstOffset;
-
- memmove(pDst, pSrc, count);
+ memmove(pDstOrigin, pSrcOrigin, count);
}
}
[DllImport("msvcrt.dll", SetLastError = false)]
- public static unsafe extern IntPtr memmove(void* dest, void* src, int count);
+ public static extern unsafe IntPtr memmove(void* dest, void* src, int count);
}
-}
+}
\ No newline at end of file
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/Program.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/Program.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/Program.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/Program.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/Properties/AssemblyInfo.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/Properties/AssemblyInfo.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/Properties/AssemblyInfo.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/Properties/AssemblyInfo.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/UnsafeAnderman.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeAnderman.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/UnsafeAnderman.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeAnderman.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/UnsafeAnderman2.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeAnderman2.cs
similarity index 52%
rename from src/DotNetCross.Memory.Copies.Benchmarks/UnsafeAnderman2.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeAnderman2.cs
index 29cbc55..9a18b82 100644
--- a/src/DotNetCross.Memory.Copies.Benchmarks/UnsafeAnderman2.cs
+++ b/src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeAnderman2.cs
@@ -29,134 +29,92 @@ public static class UnsafeAnderman2
/// Code must be optimized, in release mode and .IsHardwareAccelerated must be true for the
/// performance benefits.
///
-
public static unsafe void VectorizedCopy2(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)
{
- if (count > 512 + 64)
- {
- // TEST: Disable Array-Copy fall back
- // In-built copy faster for large arrays (vs repeated bounds checks on Vector.ctor?)
- //Array.Copy(src, srcOffset, dst, dstOffset, count);
- //return;
- }
+ const int alignment = 0x10;
+ const int mask = alignment - 1;
+
+ if (count == 0) return;
if (src == null || dst == null) throw new ArgumentNullException(nameof(src));
if (srcOffset + count > src.Length) throw new ArgumentException(nameof(src));
- if (dstOffset + count > dst.Length) throw new ArgumentException(nameof(dst));
if (count < 0 || srcOffset < 0 || dstOffset < 0) throw new ArgumentOutOfRangeException(nameof(count));
+ if (dstOffset + count > dst.Length) throw new ArgumentException(nameof(dst));
+
fixed (byte* pSrcOrigin = &src[srcOffset])
+ fixed (byte* pDstOrigin = &dst[dstOffset])
{
var pSrc = pSrcOrigin;
- fixed (byte* pDstOrigin = &dst[dstOffset])
+ var pDst = pDstOrigin;
+ if (count < 16)
{
- var pDst = pDstOrigin;
+ if (count < 8)
{
- if (count >= Vector.Count)
+ if (count < 4)
{
- while (count > Vector.Count)
+ if (count < 2)
+ {
+ *(pDst + 0) = *(pSrc + 0);
+ }
+ else
{
- Unsafe.Write(pDst, Unsafe.Read>(pSrc));
- count -= Vector.Count;
- pSrc += Vector.Count;
- pDst += Vector.Count;
+ *(short*) pDst = *(short*) pSrc;
+ *(short*) (pDst + (count & 0xf) - 2) = *(short*) (pSrc + (count & 0xf) - 2);
}
- pDst += count - Vector.Count;
- pSrc += count - Vector.Count;
- Unsafe.Write(pDst, Unsafe.Read>(pSrc));
- return;
}
-
- switch (count)
+ else
{
- case 15:
- {
- *(long*)pDst = *(long*)pSrc;
- *(long*)(pDst + 7) = *(long*)(pSrc + 7);
- return;
- }
- case 14:
- {
- *(long*)pDst = *(long*)pSrc;
- *(long*)(pDst + 6) = *(long*)(pSrc + 6);
- return;
- }
- case 13:
- {
- *(long*)pDst = *(long*)pSrc;
- *(long*)(pDst + 5) = *(long*)(pSrc + 5);
- return;
- }
- case 12:
- {
- *(long*)pDst = *(long*)pSrc;
- *(int*)(pDst + 8) = *(int*)(pSrc + 8);
- return;
- }
- case 11:
- {
- *(long*)pDst = *(long*)pSrc;
- *(int*)(pDst + 7) = *(int*)(pSrc + 7);
- return;
- }
- case 10:
- {
- *(long*)pDst = *(long*)pSrc;
- *(short*)(pDst + 8) = *(short*)(pSrc + 8);
- return;
- }
- case 9:
- {
- *(long*)pDst = *(long*)pSrc;
- *(pDst + 8) = *(pSrc + 8);
- return;
- }
- case 8:
- {
- *(long*)pDst = *(long*)pSrc;
- return;
- }
- case 7:
- {
- *(int*)pDst = *(int*)pSrc;
- *(int*)(pDst + 3) = *(int*)(pSrc + 3);
- return;
- }
- case 6:
- {
- *(int*)pDst = *(int*)pSrc;
- *(short*)(pDst + 4) = *(short*)(pSrc + 4);
- return;
- }
- case 5:
- {
- *(int*)pDst = *(int*)pSrc;
- *(pDst + 4) = *(pSrc + 4);
- return;
- }
- case 4:
- {
- *(int*)pDst = *(int*)pSrc;
- return;
- }
- case 3:
- {
- *(short*)pDst = *(short*)pSrc;
- *(pDst + 2) = *(pSrc + 2);
- return;
- }
- case 2:
- {
- *(short*)pDst = *(short*)pSrc;
- return;
- }
- case 1:
- {
- *pDst = *pSrc;
- return;
- }
- case 0:
- return;
+ *(int*) pDst = *(int*) pSrc;
+ *(int*) (pDst + (count & 0xf) - 4) = *(int*) (pSrc + (count & 0xf) - 4);
}
}
+ else
+ {
+ *(long*) pDst = *(long*) pSrc;
+ *(long*) (pDst + (count & 0xf) - 8) = *(long*) (pSrc + (count & 0xf) - 8);
+ }
+ return;
+ }
+
+ pSrc -= (long) pDst;
+ Unsafe.Write(pDst, Unsafe.Read>(pSrc + (long) pDst));
+
+ var offset = (int) ((ulong) pDst & mask);
+ count += offset - alignment;
+ pDst += alignment - offset;
+
+ while (count >= 4*Vector.Count)
+ {
+ var x1 = Unsafe.Read>(pSrc + (long) pDst);
+ var x2 = Unsafe.Read>(pSrc + (long) pDst + Vector.Count);
+ count -= 4*Vector.Count;
+ Unsafe.Write(pDst, x1);
+ Unsafe.Write(pDst + Vector.Count, x2);
+ pDst += 4*Vector.Count;
+ x1 = Unsafe.Read>(pSrc + (long) pDst - 2*Vector.Count);
+ x2 = Unsafe.Read>(pSrc + (long) pDst - Vector.Count);
+ Unsafe.Write(pDst - 2*Vector.Count, x1);
+ Unsafe.Write(pDst - Vector.Count, x2);
+ }
+ while (count >= 2*Vector.Count)
+ {
+ var x1 = Unsafe.Read>(pSrc + (long) pDst);
+ var x2 = Unsafe.Read>(pSrc + (long) pDst + Vector.Count);
+ count -= 2*Vector.Count;
+ Unsafe.Write(pDst, x1);
+ Unsafe.Write(pDst + Vector.Count, x2);
+ pDst += 2*Vector.Count;
+ }
+ while (count >= 1*Vector.Count)
+ {
+ var x1 = Unsafe.Read>(pSrc + (long) pDst);
+ count -= Vector.Count;
+ Unsafe.Write(pDst, x1);
+ pDst += Vector.Count;
+ }
+ if (count > 0)
+ {
+ pDst += count - Vector.Count;
+ Unsafe.Write(pDst, Unsafe.Read>(pSrc + (long) pDst));
}
}
}
@@ -261,14 +219,14 @@ public static unsafe void UnsafeVectorizedCopy2(byte* pDst, byte* pSrc, int coun
return;
}
case 1:
- {
- *pDst = *pSrc;
- return;
- }
+ {
+ *pDst = *pSrc;
+ return;
+ }
case 0:
- {
- return;
- }
+ {
+ return;
+ }
}
}
}
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveJamesqo.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveJamesqo.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveJamesqo.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveJamesqo.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveJamesqo2.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveJamesqo2.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveJamesqo2.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveJamesqo2.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveOriginal.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveOriginal.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveOriginal.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveOriginal.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveTannerGooding.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveTannerGooding.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveTannerGooding.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveTannerGooding.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveTannerGooding2.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveTannerGooding2.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveTannerGooding2.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemmoveTannerGooding2.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemoryCopy.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemoryCopy.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemoryCopy.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeBufferMemoryCopy.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/UnsafeCpblk.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeCpblk.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/UnsafeCpblk.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeCpblk.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/UnsafeIllyriad.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeIllyriad.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/UnsafeIllyriad.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeIllyriad.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/UnsafeNietras.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeNietras.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/UnsafeNietras.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeNietras.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/UnsafeNoChecksCopiesBenchmark.cs b/src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeNoChecksCopiesBenchmark.cs
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/UnsafeNoChecksCopiesBenchmark.cs
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/UnsafeNoChecksCopiesBenchmark.cs
diff --git a/src/DotNetCross.Memory.Copies.Benchmarks/packages.config b/src/old/DotNetCross.Memory.Copies.Benchmarks/packages.config
similarity index 100%
rename from src/DotNetCross.Memory.Copies.Benchmarks/packages.config
rename to src/old/DotNetCross.Memory.Copies.Benchmarks/packages.config
diff --git a/src/old/mov_repsb/AndermanMovsb.cs b/src/old/mov_repsb/AndermanMovsb.cs
new file mode 100644
index 0000000..461242b
--- /dev/null
+++ b/src/old/mov_repsb/AndermanMovsb.cs
@@ -0,0 +1,101 @@
+using System;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+
+namespace mov_repsb
+{
+ public static class AndermanMovsb
+ {
+ private const uint PAGE_READWRITE = 0x04;
+ private const uint PAGE_EXECUTE = 0x10;
+ private const uint PAGE_EXECUTE_READWRITE = 0x40;
+ private const uint MEM_COMMIT = 0x1000;
+ private const uint MEM_RELEASE = 0x8000;
+
+ [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, out uint lpflOldProtect);
+
+ [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
+ private static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
+
+ [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);
+
+ public delegate int MyMoveSb(ulong RCX, ulong RDX, ulong R8);
+
+ public static MyMoveSb MyAdd;
+
+ static AndermanMovsb()
+ {
+ //RAX�=�0000008377040000 RBX�=�0000000000000005 RCX�=�0000000000000004 RDX�=�0000000000000005 RSI�=�0000008300018350 RDI�=�0000000000000004 R8 �=�0000000000000006 R9 �=�000007F9C2460F84 R10�=�0000000000000000 R11�=�0000000000000000 R12�=�00000083754BDF70 R13�=�0000000000000004 R14�=�0000000000000006 R15�=�000000837555A4D0 RIP�=�0000008377040000 RSP�=�00000083754BDDF8 RBP�=�00000083754BDEA0 EFL�=�00000246
+ /*
+ 0: 49 89 fb mov r11,rdi
+ 3: 49 89 f2 mov r10,rsi
+ 6: 48 89 ce mov rsi,rcx
+ 9: 48 89 d7 mov rdi,rdx
+ c: 4c 89 c1 mov rcx,r8
+ f: f3 a4 rep movs BYTE PTR es:[rdi],BYTE PTR ds:[rsi]
+ 11: 4c 89 d6 mov rsi,r10
+ 14: 4c 89 df mov rdi,r11
+ 17: c3 ret
+ */
+ byte[] assemblyCode = { 0x49, 0x89, 0xFB, 0x49, 0x89, 0xF2, 0x48, 0x89, 0xCE, 0x48, 0x89, 0xD7, 0x4C, 0x89, 0xC1, 0xF3, 0xA4, 0x4C, 0x89, 0xD6, 0x4C, 0x89, 0xDF, 0xC3 };
+
+
+ // We need to push the code bytes into a native buffer
+
+ var bufPtr = IntPtr.Zero;
+
+ try
+ {
+ // Put the sourcecode in a native buffer
+ bufPtr = VirtualAlloc(IntPtr.Zero, (IntPtr)assemblyCode.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+
+ Marshal.Copy(assemblyCode, 0, bufPtr, assemblyCode.Length);
+ uint oldProtection;
+ var result = VirtualProtect(bufPtr, (IntPtr)assemblyCode.Length, PAGE_EXECUTE, out oldProtection);
+
+ if (!result)
+ {
+ throw new Win32Exception();
+ }
+ MyAdd = Marshal.GetDelegateForFunctionPointer(bufPtr);
+ bufPtr = IntPtr.Zero;
+ }
+ finally
+ {
+ // Free the native buffer
+ if (bufPtr != IntPtr.Zero)
+ {
+ var result = VirtualFree(bufPtr, IntPtr.Zero, MEM_RELEASE);
+ if (!result)
+ {
+ throw new Win32Exception();
+ }
+ }
+ }
+ }
+ private const int BufferSize = 1024 * 1024 * 1024;
+ private static readonly byte[] _src = new byte[BufferSize];
+ private static readonly byte[] _dst = new byte[BufferSize];
+
+ public static unsafe void VectorizedCopyAnderman()
+ {
+ for (var i = 0; i < 256; i++)
+ _src[i] = (byte)i;
+ fixed (byte* pSrcOrigin = &_src[0])
+ fixed (byte* pDstOrigin = &_dst[0])
+ {
+ var pSrc = pSrcOrigin;
+ var pDst = pDstOrigin;
+ var result1 = MyAdd((ulong)pSrc, (ulong)pDst,256);
+ for (var i = 0; i < 256; i++)
+ Console.WriteLine("Result: {0}", _dst[i]);
+ Console.ReadKey();
+
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/old/mov_repsb/Program.cs b/src/old/mov_repsb/Program.cs
new file mode 100644
index 0000000..c6c7101
--- /dev/null
+++ b/src/old/mov_repsb/Program.cs
@@ -0,0 +1,14 @@
+using System.Diagnostics;
+
+namespace mov_repsb
+{
+ internal class Program
+
+ {
+ private static void Main()
+
+ {
+ AndermanMovsb.VectorizedCopyAnderman();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/old/mov_repsb/Properties/AssemblyInfo.cs b/src/old/mov_repsb/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..1c454eb
--- /dev/null
+++ b/src/old/mov_repsb/Properties/AssemblyInfo.cs
@@ -0,0 +1,19 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("mov_repsb")]
+[assembly: AssemblyTrademark("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("7720672a-d8a5-4db9-a4f6-810fab98e3cc")]
diff --git a/src/old/mov_repsb/mov_repsb.xproj b/src/old/mov_repsb/mov_repsb.xproj
new file mode 100644
index 0000000..80bbe97
--- /dev/null
+++ b/src/old/mov_repsb/mov_repsb.xproj
@@ -0,0 +1,21 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+
+ 7720672a-d8a5-4db9-a4f6-810fab98e3cc
+ mov_repsb
+ .\obj
+ .\bin\
+ v4.6.1
+
+
+
+ 2.0
+
+
+
diff --git a/src/old/mov_repsb/project.json b/src/old/mov_repsb/project.json
new file mode 100644
index 0000000..c66185f
--- /dev/null
+++ b/src/old/mov_repsb/project.json
@@ -0,0 +1,21 @@
+{
+ "version": "1.0.0-*",
+ "buildOptions": {
+ "emitEntryPoint": true,
+ "optimize": true,
+ "allowUnsafe": true
+ },
+
+ "dependencies": {
+ "Microsoft.NETCore.App": {
+ "type": "platform",
+ "version": "1.0.0"
+ }
+ },
+
+ "frameworks": {
+ "netcoreapp1.0": {
+ "imports": "dnxcore50"
+ }
+ }
+}