рдЖрдкрдХрд╛ рдзреНрдпрд╛рди .NET рдлреНрд░реЗрдорд╡рд░реНрдХ рдФрд░ .NETCORE рдореЗрдВ рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЗ рд╡реИрд╢реНрд╡реАрдХрд░рдг рдХреА рдХреНрд╖рдорддрд╛рдУрдВ рдХреЗ рдПрдХ рдЫреЛрдЯреЗ рд╕реЗ рдЕрд╡рд▓реЛрдХрди рдХреЗ рд▓рд┐рдП рдЖрдордВрддреНрд░рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рд▓реЗрдЦ рдХрд╛ рдЙрджреНрджреЗрд╢реНрдп рдЙрди рд▓реЛрдЧреЛрдВ рдХреЛ рдЗрди рддрдХрдиреАрдХреЛрдВ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рдХрд░рд╛рдирд╛ рд╣реИ рдЬреЛ рдЙрдиреНрд╣реЗрдВ рдмрд┐рд▓реНрдХреБрд▓ рдирд╣реАрдВ рдЬрд╛рдирддреЗ рдереЗ рдФрд░ рдпрд╣ рдмрддрд╛рдирд╛ рдЪрд╛рд╣рддреЗ рдереЗ рдХрд┐ рдиреЗрдЯ рджреЗрд╢реА рдХреЗ рд▓рд┐рдП "рд╡рд╛рд╕реНрддрд╡рд┐рдХ, рд╕рдВрдХрд▓рд┐рдд" рднрд╛рд╖рд╛рдУрдВ рд╕реЗ рдмрд╣реБрдд рдкреАрдЫреЗ рдирд╣реАрдВ рд╣реИред
рд╡рд┐рдХрд╛рд╕ред
рдореИрдВ рдХреЗрд╡рд▓ рд╡реИрд╢реНрд╡реАрдХрд░рдг рддрдХрдиреАрдХреЛрдВ рдХреЛ рд╕реАрдЦрдирд╛ рд╢реБрд░реВ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдЗрд╕рд▓рд┐рдП рдпрджрд┐ рд╕рдореБрджрд╛рдп рдХрд╛ рдХреЛрдИ рд╡реНрдпрдХреНрддрд┐ рдореБрдЭреЗ рдПрдХ рд╕реНрдкрд╖реНрдЯ рдХреИрдВрдЯ рдореЗрдВ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ, рдпрд╛ рдиреАрдЪреЗ рд╡рд░реНрдгрд┐рдд рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЗ рдмреЗрд╣рддрд░ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХрд╛ рд╕реБрдЭрд╛рд╡ рджреЗрддрд╛ рд╣реИ, рддреЛ рдореИрдВ рдмреЗрддрд╣рд╛рд╢рд╛ рдЦреБрд╢ рд╣реЛ рдЬрд╛рдКрдВрдЧрд╛ред
рдереЛрдбрд╝рд╛ рд╕рд╛ рдЗрддрд┐рд╣рд╛рд╕
.NET рдореЗрдВ, SIMD рдкрд╣рд▓реА рдмрд╛рд░ .NET рдлреНрд░реЗрдорд╡рд░реНрдХ 4.6 рдХреА рд░рд┐рд▓реАрдЬ рдХреЗ рд╕рд╛рде рджрд┐рдЦрд╛рдИ рджрд┐рдпрд╛ред рдлрд┐рд░ рдкреНрд░рдХрд╛рд░ рдореИрдЯреНрд░рд┐рдХреНрд╕ 3 рдПрдХреНрд╕ 2, рдореИрдЯреНрд░рд┐рдХреНрд╕ 4 рдПрдХреНрд╕ 4, рдкреНрд▓реЗрди, рдХреНрд╡рд╛рдЯрд░реНрдирд┐рдпрди, рд╡реЗрдХреНрдЯрд░ 2, рд╡реЗрдХреНрдЯрд░ 3 рдФрд░ рд╡реЗрдХреНрдЯрд░ 4 рдХреЛ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛, рдЬрд┐рд╕рдиреЗ рд╡реЗрдХреНрдЯрд░рдХреГрдд рдЧрдгрдирд╛ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреА рдЕрдиреБрдорддрд┐ рджреАред рдмрд╛рдж рдореЗрдВ, рд╡реЗрдХреНрдЯрд░ <T> рдкреНрд░рдХрд╛рд░ рдХреЛ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛, рдЬрд┐рд╕рдиреЗ рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЛ рд╡реЗрдХреНрдЯрд░ рдХрд░рдиреЗ рдХреЗ рдЕрдзрд┐рдХ рдЕрд╡рд╕рд░ рдкреНрд░рджрд╛рди рдХрд┐рдПред рд▓реЗрдХрд┐рди рдХрдИ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдЕрднреА рднреА рдирд╛рдЦреБрд╢ рдереЗ рдХреНрдпреЛрдВрдХрд┐ рдЙрдкрд░реЛрдХреНрдд рдкреНрд░рдХрд╛рд░реЛрдВ рдиреЗ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреЗ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЗ рдкреНрд░рд╡рд╛рд╣ рдХреЛ рд╕реАрдорд┐рдд рдХрд░ рджрд┐рдпрд╛ рдФрд░ рдЖрдзреБрдирд┐рдХ рдкреНрд░реЛрд╕реЗрд╕рд░ рдХреЗ SIMD рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреА рдкреВрд░реА рд╢рдХреНрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреАред рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╣рдорд╛рд░реЗ рд╕рдордп рдореЗрдВ, .NET рдХреЛрд░ 3.0 рдкреВрд░реНрд╡рд╛рд╡рд▓реЛрдХрди рдореЗрдВ, System.Runtime.Intrinsics рдирд╛рдо рд╕реНрдерд╛рди рджрд┐рдЦрд╛рдИ рджрд┐рдпрд╛ рд╣реИ, рдЬреЛ рдирд┐рд░реНрджреЗрд╢ рдЪреБрдирдиреЗ рдореЗрдВ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╕реНрд╡рддрдВрддреНрд░рддрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЧрддрд┐ рдореЗрдВ рд╕рд░реНрд╡реЛрддреНрддрдо рдкрд░рд┐рдгрд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ RyuJit рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдФрд░ рдпрд╛ рддреЛ x64 рдкрд░ рдирд┐рд░реНрдорд╛рдг рдХрд░реЗрдВ рдпрд╛ 32-рдмрд┐рдЯ рдХреЛ рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рджреЗрдВ рдФрд░ AnyCPU рдкрд░ рдирд┐рд░реНрдорд╛рдг рдХрд░реЗрдВред рд╕рднреА рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдЬрд┐рдиреНрд╣реЗрдВ рдореИрдВрдиреЗ Intel Core i7-6700 рдкреНрд░реЛрд╕реЗрд╕рд░ 3.40GHz (Skylake) рдХреЗ рд╕рд╛рде рдХрдВрдкреНрдпреВрдЯрд░ рдкрд░ рдЪрд▓рд╛рдпрд╛ рдерд╛ред
рд╕рд░рдгреА рдХреЗ рддрддреНрд╡реЛрдВ рдХреЛ рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ рд▓рд┐рдЦреЗрдВ
рдореИрдВрдиреЗ рдХреНрд▓рд╛рд╕рд┐рдХ рд╕рдорд╕реНрдпрд╛ рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛, рдЬреЛ рдЕрдХреНрд╕рд░ рд╡реЗрдХреНрдЯрд░рд╛рдЗрдЬреЗрд╢рди рдХреА рдмрд╛рдд рдЖрдиреЗ рдкрд░ рд▓рд┐рдЦрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рд╕рд░рдгреА рдХреЗ рддрддреНрд╡реЛрдВ рдХрд╛ рдпреЛрдЧ рдЦреЛрдЬрдиреЗ рдХрд╛ рдХрд╛рд░реНрдп рд╣реИред рд╣рдо рдЗрд╕ рдХрд╛рд░реНрдп рдХреЗ рдЪрд╛рд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд▓рд┐рдЦреЗрдВрдЧреЗ, рд╣рдо рдПрд░реЗ рд╕рд░рдгреА рдХреЗ рддрддреНрд╡реЛрдВ рдХреЛ рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдХрд░реЗрдВрдЧреЗ:
рд╕рдмрд╕реЗ рд╕реНрдкрд╖реНрдЯ рд╣реИ
public int Naive() { int result = 0; foreach (int i in Array) { result += i; } return result; }
LINQ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛
public long LINQ() => Array.Aggregate<int, long>(0, (current, i) => current + i);
System.Numerics рд╕реЗ рд╡реИрдХреНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛:
public int Vectors() { int vectorSize = Vector<int>.Count; var accVector = Vector<int>.Zero; int i; var array = Array; for (i = 0; i < array.Length - vectorSize; i += vectorSize) { var v = new Vector<int>(array, i); accVector = Vector.Add(accVector, v); } int result = Vector.Dot(accVector, Vector<int>.One); for (; i < array.Length; i++) { result += array[i]; } return result; }
System.Runtime.Intrinsics рд╕реНрдерд╛рди рд╕реЗ рдХреЛрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛:
public unsafe int Intrinsics() { int vectorSize = 256 / 8 / 4; var accVector = Vector256<int>.Zero; int i; var array = Array; fixed (int* ptr = array) { for (i = 0; i < array.Length - vectorSize; i += vectorSize) { var v = Avx2.LoadVector256(ptr + i); accVector = Avx2.Add(accVector, v); } } int result = 0; var temp = stackalloc int[vectorSize]; Avx2.Store(temp, accVector); for (int j = 0; j < vectorSize; j++) { result += temp[j]; } for (; i < array.Length; i++) { result += array[i]; } return result; }
рдореИрдВрдиреЗ рдЕрдкрдиреЗ рдХрдВрдкреНрдпреВрдЯрд░ рдкрд░ рдЗрди 4 рддрд░реАрдХреЛрдВ рдкрд░ рдПрдХ рдмреЗрдВрдЪрдорд╛рд░реНрдХ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдФрд░ рдпрд╣ рдкрд░рд┐рдгрд╛рдо рдорд┐рд▓рд╛:
рдпрд╣ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рд╕реНрдкрд╖реНрдЯ рд╕рдорд╛рдзрд╛рди рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рд╡реИрдХреНрдЯрд░ рдФрд░ рдЗрдВрдЯреНрд░рд┐рдВрд╕рд┐рдХреНрд╕ рдХреЗ рд╕рдорд╛рдзрд╛рди рдмрд╣реБрдд рддреЗрдЬреА рд╕реЗ рдФрд░ LINQ рдХреЗ рд╕рд╛рде рд╣реИрдВред рдЕрдм рд╣рдореЗрдВ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ рдХрд┐ рдЗрди рджреЛ рддрд░реАрдХреЛрдВ рдореЗрдВ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИред
рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╡реИрдХреНрдЯрд░ рд╡рд┐рдзрд┐ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ:
рд╡реИрдХреНрдЯрд░ public int Vectors() { int vectorSize = Vector<int>.Count; var accVector = Vector<int>.Zero; int i; var array = Array; for (i = 0; i < array.Length - vectorSize; i += vectorSize) { var v = new Vector<int>(array, i); accVector = Vector.Add(accVector, v); } int result = Vector.Dot(accVector, Vector<int>.One); for (; i < array.Length; i++) { result += array[i]; } return result; }
- int VectorSize = рд╡реЗрдХреНрдЯрд░ <int> .Count; - рдпрд╣ рдПрдХ рд╡реЗрдХреНрдЯрд░ рдореЗрдВ рдХрд┐рддрдиреЗ 4 рдмрд╛рдЗрдЯ рдирдВрдмрд░ рд╣реИрдВред рдпрджрд┐ рд╣рд╛рд░реНрдбрд╡реЗрдпрд░ рддреНрд╡рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдорд╛рди рджрд┐рдЦрд╛рддрд╛ рд╣реИ рдХрд┐ рдПрдХ SIMD рд░рдЬрд┐рд╕реНрдЯрд░ рдореЗрдВ рдХрд┐рддрдиреЗ 4-рдмрд╛рдЗрдЯ рдирдВрдмрд░ рд░рдЦреЗ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рджрд┐рдЦрд╛рддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреЗ рдХрд┐рддрдиреЗ рддрддреНрд╡ рдЖрдк рд╕рдорд╛рдирд╛рдВрддрд░ рдореЗрдВ рд╕рдВрдЪрд╛рд▓рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ;
- accVector - рдПрдХ рд╡реЗрдХреНрдЯрд░ рдЬрд┐рд╕рдореЗрдВ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдкрд░рд┐рдгрд╛рдо рдЬрдорд╛ рд╣реЛрдЧрд╛;
var v = рдирдпрд╛ рд╡реЗрдХреНрдЯрд░ <int> (рд╕рд░рдгреА, i); - рдбреЗрдЯрд╛ рдХреЛ рдЗрдВрдбреЗрдХреНрд╕ рд╕реЗ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реБрдП, рд╕рд░рдгреА рд╕реЗ, рдПрдХ рдирдпрд╛ рд╡реЗрдХреНрдЯрд░ рд╡реА рдореЗрдВ рд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╡реЗрдХреНрдЯрд░рд╕рд╛рдЗрдЬрд╝ рдбреЗрдЯрд╛ рд▓реЛрдб рд╣реЛ рдЬрд╛рдПрдЧрд╛ред - accVector = Vector.Add (accVector, v); - рджреЛ рд╡реИрдХреНрдЯрд░ рдЬреЛрдбрд╝реЗ рдЬрд╛рддреЗ рд╣реИрдВред
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдРрд░реЗ 8 рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ: {0, 1, 2, 3, 4, 5, 6, 7} рдФрд░ рд╡реЗрдХреНрдЯрд░рд╕рд╛рдЗрдЬ == 4, рдлрд┐рд░:
рд▓реВрдк accVector рдХреЗ рдкрд╣рд▓реЗ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдореЗрдВ = {0, 0, 0, 0}, v = {0, 1, 2, 3}, accVector рдореЗрдВ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рдмрд╛рдж рдпрд╣ рд╣реЛрдЧрд╛: {0, 0, 0, 0} + {0, 1, 2 , 3} = {0, 1, 2, 3}ред
рджреВрд╕рд░реА рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдореЗрдВ, v = {4, 5, 6, 7} рдФрд░ рдЗрд╕рдХреЗ рдмрд╛рдж accVector = {0, 1, 2, 3} + {4, 5, 6, 7} = {4, 6, 8, 10}ред - рдпрд╣ рдХреЗрд╡рд▓ рдХрд┐рд╕реА рди рдХрд┐рд╕реА рд░реВрдк рдореЗрдВ рд╡реЗрдХреНрдЯрд░ рдХреЗ рд╕рднреА рддрддреНрд╡реЛрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛ рд░рд╣рддрд╛ рд╣реИ, рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдо рдЗрдХрд╛рдЗрдпреЛрдВ рд╕реЗ рднрд░реЗ рд╡реЗрдХреНрдЯрд░ рджреНрд╡рд╛рд░рд╛ рд╕реНрдХреЗрд▓рд░ рдЧреБрдгрди рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ: int result = Vector.Dot (accVector, рд╡реЗрдХреНрдЯрд░ <int .One);
рдлрд┐рд░ рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛: {4, 6, 8, 10} {1, 1, 1, 1} = 4 1 + 6 1 + 8 1 + 10 * 1 = 28ред - рдЕрдВрдд рдореЗрдВ, рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ, рддреЛ рд╕рдВрдЦреНрдпрд╛рдПрдБ рдЬреЛрдбрд╝реА рдЬрд╛рддреА рд╣реИрдВ рдЬреЛ рдЕрдВрддрд┐рдо рд╡реЗрдХреНрдЯрд░ рдореЗрдВ рдлрд┐рдЯ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИрдВред
рдпрджрд┐ рдЖрдк рдЖрдВрддрд░рд┐рдХ рдкрджреНрдзрддрд┐ рдХреЛрдб рдХреЛ рджреЗрдЦрддреЗ рд╣реИрдВ:
intrinsics public unsafe int Intrinsics() { int vectorSize = 256 / 8 / 4; var accVector = Vector256<int>.Zero; int i; var array = Array; fixed (int* ptr = array) { for (i = 0; i < array.Length - vectorSize; i += vectorSize) { var v = Avx2.LoadVector256(ptr + i); accVector = Avx2.Add(accVector, v); } } int result = 0; var temp = stackalloc int[vectorSize]; Avx2.Store(temp, accVector); for (int j = 0; j < vectorSize; j++) { result += temp[j]; } for (; i < array.Length; i++) { result += array[i]; } return result; }
рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдХреБрдЫ рдЕрдкрд╡рд╛рджреЛрдВ рдХреЗ рд╕рд╛рде рд╡реИрдХреНрдЯрд░ рдХреЗ рд╕рдорд╛рди рд╣реИ:
рджреЛ рд╕рд░рдгрд┐рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░реЗрдВ
рдмрд╛рдЗрдЯреНрд╕ рдХреЗ рджреЛ рд╕рд░рдгрд┐рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣ рд╡рд╣ рд╕рдорд╕реНрдпрд╛ рд╣реИ рдЬрд┐рд╕рдХреЗ рдХрд╛рд░рдг рдореИрдВрдиреЗ .NET рдореЗрдВ SIMD рд╕реАрдЦрдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛ред рдлрд┐рд░, рд╣рдо рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдХреЗ рд▓рд┐рдП рдХрдИ рддрд░реАрдХреЗ рд▓рд┐рдЦреЗрдВрдЧреЗ, рд╣рдо рджреЛ рд╕рд░рдгрд┐рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░реЗрдВрдЧреЗ: ArrayA рдФрд░ ArrayB:
рд╕рдмрд╕реЗ рд╕реНрдкрд╖реНрдЯ рд╕рдорд╛рдзрд╛рди:
public bool Naive() { for (int i = 0; i < ArrayA.Length; i++) { if (ArrayA[i] != ArrayB[i]) return false; } return true; }
LINQ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рдорд╛рдзрд╛рди:
public bool LINQ() => ArrayA.SequenceEqual(ArrayB);
MemCmp рд╕рдорд╛рд░реЛрд╣ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рдорд╛рдзрд╛рди:
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)] static extern int memcmp(byte[] b1, byte[] b2, long count); public bool MemCmp() => memcmp(ArrayA, ArrayB, ArrayA.Length) == 0;
System.Numerics рд╕реЗ рд╡реИрдХреНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛:
public bool Vectors() { int vectorSize = Vector<byte>.Count; int i = 0; for (; i < ArrayA.Length - vectorSize; i += vectorSize) { var va = new Vector<byte>(ArrayA, i); var vb = new Vector<byte>(ArrayB, i); if (!Vector.EqualsAll(va, vb)) { return false; } } for (; i < ArrayA.Length; i++) { if (ArrayA[i] != ArrayB[i]) return false; } return true; }
рдЖрдВрддрд░рд┐рдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛:
public unsafe bool Intrinsics() { int vectorSize = 256 / 8; int i = 0; const int equalsMask = unchecked((int) (0b1111_1111_1111_1111_1111_1111_1111_1111)); fixed (byte* ptrA = ArrayA) fixed (byte* ptrB = ArrayB) { for (; i < ArrayA.Length - vectorSize; i += vectorSize) { var va = Avx2.LoadVector256(ptrA + i); var vb = Avx2.LoadVector256(ptrB + i); var areEqual = Avx2.CompareEqual(va, vb); if (Avx2.MoveMask(areEqual) != equalsMask) { return false; } } for (; i < ArrayA.Length; i++) { if (ArrayA[i] != ArrayB[i]) return false; } return true; } }
рдореЗрд░реЗ рдХрдВрдкреНрдпреВрдЯрд░ рдкрд░ рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдХрд╛ рдкрд░рд┐рдгрд╛рдо:
рдЗрди рддрд░реАрдХреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рднреА рдХреЛрдб, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИ, рдЖрдВрддрд░рд┐рдХ рдореЗрдВ рджреЛ рд▓рд╛рдЗрдиреЛрдВ рдХреЗ рдЕрдкрд╡рд╛рдж рдХреЗ рд╕рд╛рде:
var areEqual = Avx2.CompareEqual(va, vb); if (Avx2.MoveMask(areEqual) != equalsMask) { return false; }
рдкрд╣рд▓реЗ рдореЗрдВ, рджреЛ рд╡реИрдХреНрдЯрд░ рдХреА рд╕рдорд╛рдирддрд╛ рдХреЗ рд▓рд┐рдП рддреБрд▓рдирд╛ рдХреА рдЬрд╛рддреА рд╣реИ рдФрд░ рдкрд░рд┐рдгрд╛рдо рдХреЛ рдЗрд░рд┐рдХреНрд╡рд╛рд▓ рд╡реЗрдХреНрдЯрд░ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рд╕рднреА рдмрд┐рдЯреНрд╕ рдХреЛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕реНрдерд╛рди рдкрд░ рдПрдХ рддрддреНрд╡ рдореЗрдВ 1 рдкрд░ рд╕реЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдпрджрд┐ va рдФрд░ vb рдореЗрдВ рд╕рдВрдмрдВрдзрд┐рдд рддрддреНрд╡ рд╕рдорд╛рди рд╣реЛрдВред рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рдЕрдЧрд░ рдмрд╛рдЗрдЯреНрд╕ рд╡реАрдП рдФрд░ рд╡реАрдмреА рд╕реЗ рд╡реИрдХреНрдЯрд░ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдмрд░рд╛рдмрд░ рд╣реИрдВ, рддреЛ рдЗрд╕ рддрд░рд╣ рд╕реЗ рд╕рднреА рддрддреНрд╡реЛрдВ рдореЗрдВ 255 (11111111b) рдХреЗ рдмрд░рд╛рдмрд░ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдХреНрдпреЛрдВрдХрд┐ Avx2.CompareEqual _mm256_cmpeq_epi8 рдкрд░ рдПрдХ рдЖрд╡рд░рдг рд╣реИ, рддрдм рдЗрдВрдЯреЗрд▓ рд╕рд╛рдЗрдЯ рдкрд░ рдЖрдк рдЗрд╕ рдСрдкрд░реЗрд╢рди рдХрд╛ рдЫрджреНрдо рдХреЛрдб рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ:
рдПрдХ рд╡реЗрдХреНрдЯрд░ рд╕реЗ MoveMask рд╡рд┐рдзрд┐ рдПрдХ 32-рдмрд┐рдЯ рд╕рдВрдЦреНрдпрд╛ рдмрдирд╛рддреА рд╣реИред рдмрд┐рдЯ рдорд╛рди рд╡реЗрдХреНрдЯрд░ рдХреЗ 32 рдПрдХрд▓-рдмрд╛рдЗрдЯ рддрддреНрд╡реЛрдВ рдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдХреЗ рдЙрдЪреНрдЪ рдмрд┐рдЯреНрд╕ рд╣реИрдВред рд╕реНрдпреВрдбреЛрдХреЛрдб рдпрд╣рд╛рдБ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ ред
рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдпрджрд┐ va рдФрд░ vb рдореЗрдВ рдХреБрдЫ рдмрд╛рдЗрдЯреНрд╕ рдореЗрд▓ рдирд╣реАрдВ рдЦрд╛рддреЗ рд╣реИрдВ, рддреЛ рд╕рдорд╛рдиреНрдп рдореЗрдВ рдмрд╛рдЗрдЯреНрд╕ 0 рд╣реЛрдВрдЧреЗ, рдЗрд╕рд▓рд┐рдП рдЗрди рдмрд╛рдЗрдЯреНрд╕ рдХреЗ рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд┐рдЯреНрд╕ рднреА 0 рд╣реЛрдВрдЧреЗ, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ Avx2 .Mask рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рд╕рдВрдмрдВрдзрд┐рдд рдмрд┐рдЯреНрд╕ рднреА 0 рдФрд░ рддреБрд▓рдирд╛рддреНрдордХ рд╣реЛрдВрдЧреЗред рдмрд░рд╛рдмрд░реА рдХреЗ рд╕рд╛рде рдХрд╛рдо рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред
рдЪрд▓реЛ рдПрдХ рдЫреЛрдЯреЗ рд╕реЗ рдЙрджрд╛рд╣рд░рдг рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рддреЗ рд╣реИрдВ, рдпрд╣ рдорд╛рдирддреЗ рд╣реБрдП рдХрд┐ рд╡реЗрдХреНрдЯрд░ рдХреА рд▓рдВрдмрд╛рдИ 8 рдмрд╛рдЗрдЯреНрд╕ рд╣реИ (рдпрд╣ рд▓рд┐рдЦрдирд╛ рдХрдо рдерд╛):
- рдЪрд▓реЛ va = {100, 10, 20, 30, 100, 40, 50, 100}, рдФрд░ vb = {100, 20, 10, 30, 100, 40, 80, 90};
- рдлрд┐рд░ рдИрдХреНрд╡рд▓ {255, 0, 0, 255, 255, 255, 0, 0} рдХреЗ рдмрд░рд╛рдмрд░ рд╣реЛрдЧрд╛;
- рдореВрд╡рдорд╕реНрдХ рд╡рд┐рдзрд┐ 10011100 рдмреА рд▓реМрдЯреЗрдЧреА, рдЬрд┐рд╕реЗ рдорд╛рд╕реНрдХ 11111111 рдмреА рдХреЗ рд╕рд╛рде рддреБрд▓рдирд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рдХреНрдпреЛрдВрдХрд┐ рдЪреВрдВрдХрд┐ рдпреЗ рдореБрдЦреМрдЯреЗ рдЕрд╕рдорд╛рди рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рд╡реИрдХреНрдЯрд░ va рдФрд░ vb рд╕рдорд╛рди рдирд╣реАрдВ рд╣реИрдВред
рдЧрдгрдирд╛ рдХрд░реЗрдВ рдХрд┐ рд╕рдВрдЧреНрд░рд╣ рдореЗрдВ рдПрдХ рддрддреНрд╡ рдХрд┐рддрдиреА рдмрд╛рд░ рд╣реЛрддрд╛ рд╣реИ
рдХрднреА-рдХрднреА рдпрд╣ рдЧрдгрдирд╛ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ рдХрд┐рд╕реА рд╕рдВрдЧреНрд░рд╣ рдореЗрдВ рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рддрддреНрд╡ рдХреЛ рдХрд┐рддрдиреА рдмрд╛рд░ рдкрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЗрд╕ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЛ рднреА рддреНрд╡рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЖрдЗрдП рддреБрд▓рдирд╛ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рддрд░реАрдХреЗ рд▓рд┐рдЦреЗрдВ, рд╣рдо рдПрд░реЗ рд╕рд░рдгреА рдореЗрдВ рдЖрдЗрдЯрдо рддрддреНрд╡ рдХреА рддрд▓рд╛рд╢ рдХрд░реЗрдВрдЧреЗред
рд╕рдмрд╕реЗ рд╕реНрдкрд╖реНрдЯ:
public int Naive() { int result = 0; foreach (int i in Array) { if (i == Item) { result++; } } return result; }
LINQ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░:
public int LINQ() => Array.Count(i => i == Item);
System.Numerics.Vectors рд╕реЗ рд╡реИрдХреНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛:
public int Vectors() { var mask = new Vector<int>(Item); int vectorSize = Vector<int>.Count; var accResult = new Vector<int>(); int i; var array = Array; for (i = 0; i < array.Length - vectorSize; i += vectorSize) { var v = new Vector<int>(array, i); var areEqual = Vector.Equals(v, mask); accResult = Vector.Subtract(accResult, areEqual); } int result = 0; for (; i < array.Length; i++) { if (array[i] == Item) { result++; } } result += Vector.Dot(accResult, Vector<int>.One); return result; }
рдЖрдВрддрд░рд┐рдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛:
public unsafe int Intrinsics() { int vectorSize = 256 / 8 / 4;
рдореЗрд░реЗ рдХрдВрдкреНрдпреВрдЯрд░ рдкрд░ рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдХрд╛ рдкрд░рд┐рдгрд╛рдо:
рд╡реИрдХреНрдЯрд░ рдФрд░ рдЗрдВрдЯреНрд░рд┐рдирд┐рдХреНрд╕ рд╡рд┐рдзрд┐рдпрд╛рдВ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рддрд░реНрдХ рдореЗрдВ рд╕рдорд╛рди рд╣реИрдВ, рдЕрдВрддрд░ рдХреЗрд╡рд▓ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕рдВрдЪрд╛рд▓рди рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ рд╣реИрдВред рд╕рдордЧреНрд░ рд░реВрдк рдореЗрдВ рд╡рд┐рдЪрд╛рд░ рд╣реИ:
- рдПрдХ рдореБрдЦреМрдЯрд╛ рд╡реЗрдХреНрдЯрд░ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рд╕рдВрдЦреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рддрддреНрд╡ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реЛрддреА рд╣реИ;
- рд╕рд░рдгреА рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╡реЗрдХреНрдЯрд░ v рдореЗрдВ рд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдорд╛рд╕реНрдХ рдХреЗ рд╕рд╛рде рддреБрд▓рдирд╛ рдХреА рдЬрд╛рддреА рд╣реИ, рдлрд┐рд░ рд╕рднреА рдмрд┐рдЯреНрд╕ рдХреЛ рд╕рдорд╛рди рддрддреНрд╡реЛрдВ рдореЗрдВ рд╕реЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред areEqual ints рд╕реЗ рдПрдХ рд╡реЗрдХреНрдЯрд░ рд╣реИ, рддреЛ рдпрджрд┐ рдЖрдк рдПрдХ рддрддреНрд╡ рдХреЗ рд╕рднреА рдмрд┐рдЯреНрд╕ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ рдЗрд╕ рддрддреНрд╡ рдореЗрдВ -1 рдорд┐рд▓рддрд╛ рд╣реИ ((int) (1111_1111_1111_1111_1111_1111_1111_1111b == -1);
- рд╡реЗрдХреНрдЯрд░ areEqual рдХреЛ accVector рд╕реЗ рдШрдЯрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдлрд┐рд░ accVector рдХреЛ рдЗрд╕ рдмрд╛рдд рдХрд╛ рдпреЛрдЧ рд╣реЛрдЧрд╛ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рд╡реИрдХреНрдЯрд░ v рдореЗрдВ рдХрд┐рддрдиреА рдмрд╛рд░ рдЖрдЗрдЯрдо рддрддреНрд╡ рд╣реБрдЖ рд╣реИ рдкреНрд░рддреНрдпреЗрдХ рд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП (рдорд╛рдЗрдирд╕ рдорд┐рдирдЯ рдПрдХ рдкреНрд▓рд╕ рджреЗрддрд╛ рд╣реИ)ред
рд▓реЗрдЦ рдХреЗ рд╕рднреА рдХреЛрдб GitHub рдкрд░ рджреЗрдЦреЗ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ
рдирд┐рд╖реНрдХрд░реНрд╖
рдореИрдВрдиреЗ рдХреЗрд╡рд▓ рд╕рдВрднрд╛рд╡рдирд╛рдУрдВ рдХреЗ рдПрдХ рдмрд╣реБрдд рдЫреЛрдЯреЗ рд╣рд┐рд╕реНрд╕реЗ рдХреА рдЬрд╛рдВрдЪ рдХреА рдЬреЛ .NET рдХрдореНрдкреНрдпреВрдЯрд┐рдВрдЧ рдХрдореНрдкреНрдпреВрдЯрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред X86 рдХреЗ рддрд╣рдд .NETCORE рдореЗрдВ рдЙрдкрд▓рдмреНрдз рдЖрдВрддрд░рд┐рдХ рдХреА рдкреВрд░реНрдг рдФрд░ рдЕрджреНрдпрддрд┐рдд рд╕реВрдЪреА рдХреЗ рд▓рд┐рдП, рдЖрдк рд╕реНрд░реЛрдд рдХреЛрдб рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдЖрдВрддрд░рд┐рдХ рдХреЗ рд╕рд╛рд░рд╛рдВрд╢ рдореЗрдВ C # рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ C рдХреА рджреБрдирд┐рдпрд╛ рдХрд╛ рдЕрдкрдирд╛ рдирд╛рдо рд╣реИ, рдЬреЛ рдЗрд╕ рдЖрдВрддрд░рд┐рдХ рдХреЗ рдЙрджреНрджреЗрд╢реНрдп рдФрд░ рдореМрдЬреВрджрд╛ C ++ / C рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЗ рдЕрдиреБрд╡рд╛рдж рдХреА рд╕рдордЭ рдХреЛ рдЖрд╕рд╛рди рдмрдирд╛рддрд╛ рд╣реИред System.Numerics.Vector рдкреНрд░рд▓реЗрдЦрди msdn рдкрд░ рдЙрдкрд▓рдмреНрдз рд╣реИред
рдореЗрд░реА рд░рд╛рдп рдореЗрдВ, .NET рдХрд╛ C ++ рд╕реЗ рдЕрдзрд┐рдХ рд▓рд╛рдн рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЬреЗрдЖрдИрдЯреА рд╕рдВрдХрд▓рди рдХреНрд▓рд╛рдЗрдВрдЯ рдорд╢реАрди рдкрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╣реЛрддрд╛ рд╣реИ, рдлрд┐рд░ рдХрдВрдкрд╛рдЗрд▓рд░ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХреНрд▓рд╛рдЗрдВрдЯ рдкреНрд░реЛрд╕реЗрд╕рд░ рдХреЗ рд▓рд┐рдП рдХреЛрдб рдХрд╛ рдЕрдиреБрдХреВрд▓рди рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдЕрдзрд┐рдХрддрдо рдкреНрд░рджрд░реНрд╢рди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЙрд╕реА рд╕рдордп, рддреЗрдЬ рдХреЛрдб рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдПрдХ рднрд╛рд╖рд╛ рдФрд░ рдкреНрд░реМрджреНрдпреЛрдЧрд┐рдХреА рдХреЗ рдврд╛рдВрдЪреЗ рдХреЗ рднреАрддрд░ рд░рд╣ рд╕рдХрддрд╛ рд╣реИред
UPD (09/15/2019):
рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдореЗрдВ рдПрдХ рдЬрд╛рдо рдерд╛рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдореЗрдВ, рдореИрдВрдиреЗ IterationSetup рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛, рдЬреЛ рдХрд┐, рдЬреИрд╕рд╛ рдХрд┐ рдпрд╣ рдирд┐рдХрд▓рд╛, рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдмрд╣реБрдд рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдЬреЛ 100ms рд╕реЗ рдХрдо рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рдЖрдк рдЗрд╕реЗ GlobalSetup рдкрд░ рдлрд┐рд░ рд╕реЗ рдмрдирд╛рддреЗ рд╣реИрдВ, рддреЛ рдкрд░рд┐рдгрд╛рдо рдЗрд╕ рддрд░рд╣ рд╣реЛрдВрдЧреЗред
рд╕рд░рдгреА рддрддреНрд╡реЛрдВ рдХрд╛ рдпреЛрдЧ:
рджреЛ рд╕рд░рдгрд┐рдпреЛрдВ рдХреА рддреБрд▓рдирд╛:
рдХрд┐рд╕реА рд╕рд░рдгреА рдореЗрдВ рдХрд┐рд╕реА рддрддреНрд╡ рдХреЗ рд╣реЛрдиреЗ рдХреА рд╕рдВрдЦреНрдпрд╛: