├── .github
└── FUNDING.yml
├── .gitignore
├── DoDSamples.sln
├── DoDSamples
├── DoDSamples.csproj
├── Program.cs
└── Samples
│ ├── AOSvsSOA.cs
│ ├── ArrayEnumerableByRef.cs
│ ├── Benchmarks
│ ├── InstructionAndDataDependency.cs
│ ├── OOPvsDoDParsers.cs
│ ├── RefListvsList.cs
│ └── RowsVsCols.cs
│ ├── BitOperations.cs
│ ├── BlockList.cs
│ ├── CacheSize.cs
│ ├── InstructionLevelDependency.cs
│ ├── MemoryModelDeadlock.cs
│ ├── POParser
│ ├── DoDPOParser_v1.cs
│ ├── DoDPOParser_v1a.cs
│ ├── DoDPOParser_v2.cs
│ ├── DoDPOParser_v2a.cs
│ ├── DoDPOParser_v3.cs
│ ├── DoDPOParser_v3a.cs
│ ├── DoDPOParser_v4.cs
│ ├── DoDPOParser_v5.cs
│ ├── OOPParser_Fast.cs
│ ├── OOPParser_Slow.cs
│ ├── POGenerator.cs
│ └── Sample.po
│ ├── RefList.cs
│ ├── ReferenceHelpers.cs
│ ├── SIMD.cs
│ ├── SOAwithSIMD.cs
│ ├── Tests
│ ├── PoParserTests.cs
│ └── RowsVsColsTests.cs
│ └── Utils.cs
├── LICENSE
└── README.md
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 | custom: ['https://www.buymeacoffee.com/LevelUp']
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio.
3 | ################################################################################
4 |
5 | /DoDSamples/bin
6 | /DoDSamples/obj
7 |
--------------------------------------------------------------------------------
/DoDSamples.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29613.14
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DoDSamples", "DoDSamples\DoDSamples.csproj", "{3EA7FF30-3668-40EE-98A3-AF97EBBAF2EE}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {3EA7FF30-3668-40EE-98A3-AF97EBBAF2EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {3EA7FF30-3668-40EE-98A3-AF97EBBAF2EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {3EA7FF30-3668-40EE-98A3-AF97EBBAF2EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {3EA7FF30-3668-40EE-98A3-AF97EBBAF2EE}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {C2EF3999-A95E-4F75-93AA-E9BC82B5785F}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/DoDSamples/DoDSamples.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.1
6 |
7 |
8 |
9 | false
10 | true
11 | x64
12 |
13 |
14 |
15 | true
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Always
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/DoDSamples/Program.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Running;
2 | using DoDSamples.Samples;
3 | using DoDSamples.Samples.Benchmarks;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Runtime.Intrinsics;
7 | using System.Runtime.Intrinsics.X86;
8 |
9 | namespace DoDSamples
10 | {
11 | class Program
12 | {
13 | static void Main(string[] args)
14 | {
15 |
16 |
17 |
18 | /////////////////
19 | // Rows vs Cols.
20 | /////////////////
21 |
22 | //
23 | // Columns Array Traversal.
24 | //
25 | //RowsVsColsTests.Cols();
26 | //
27 | // Rows Array Traversal.
28 | //
29 | //RowsVsColsTests.Rows();
30 |
31 | /////////////////////////////////////
32 | // PO File Parser - Sum the Amount.
33 | /////////////////////////////////////
34 |
35 | //
36 | // Regex parser.
37 | //
38 | //POParserTests.TestAmountPO_Regex();
39 | //
40 | // State Machine OOP Parser.
41 | //
42 | //POParserTests.TestAmountPO_OOP_StateMachine();
43 | //
44 | // State Machine DoD Parser.
45 | //
46 | //POParserTests.TestAmountPO_DoD_StateMachine();
47 | //
48 | // State Machine DoD Parser using split.
49 | //
50 | //POParserTests.TestAmountPO_DoD_StateMachine_Split();
51 | //
52 | // State Machine DoD Parser using hot/cold split.
53 | //
54 | //POParserTests.TestAmountPO_DoD_SateMachine_HotColdSplit();
55 | //
56 | // Fixed DoD Parsers
57 | //
58 | //POParserTests.TestAmountPO_DoD_StateMachineFix();
59 | //POParserTests.TestAmountPO_DoD_SateMachine_SplitFix();
60 | //POParserTests.TestAmountPO_DoD_SateMachine_HotColdSplitFix();
61 |
62 | //
63 | // DoD SOA
64 | //
65 | //POParserTests.TestAmountPO_DoD_SoA();
66 | //POParserTests.TestAmountPO_DoD_SoA_SIMD();
67 |
68 |
69 | //////////////////////////////////////////////
70 | // PO File Parser - Notes Split And To Lower.
71 | //////////////////////////////////////////////
72 |
73 | //
74 | // State Machine OOP Split
75 | //
76 | //POParserTests.TestNotesPO_OOP_Split();
77 | //
78 | // State Machine DoD Split
79 | //
80 | //POParserTests.TestNotesPO_DoD_Split();
81 |
82 | //
83 | // State Machine OOP ToLower
84 | //
85 | //POParserTests.TestNotesToLowerPO_OOP();
86 | //
87 | // State Machine DoD ToLower
88 | //
89 | //POParserTests.TestNotesToLowerPO_DoD();
90 |
91 |
92 | //var summary = BenchmarkRunner.Run();
93 | //var summary = BenchmarkRunner.Run();
94 | //var summary = BenchmarkRunner.Run();
95 | var summary = BenchmarkRunner.Run();
96 |
97 |
98 | //SIMDSum simd = new SIMDSum();
99 |
100 | // Utils.Measure(() => simd.Sum(new int[128*1024*1024]));
101 | // Utils.Measure(() => simd.SumVectorizedSse2(array));
102 |
103 |
104 | //MemoryModelDeadlock memoryModelDeadlock = new MemoryModelDeadlock();
105 | //Utils.Measure(memoryModelDeadlock.SpinLockTest);
106 |
107 | //AOSvsSOA soa = new AOSvsSOA();
108 | //Utils.Measure(soa.TestSOA);
109 |
110 | //CacheSize c = new CacheSize();
111 |
112 | //InstructionLevelDependency ld = new InstructionLevelDependency();
113 | //Utils.Measure(ld.TestInDependant);
114 |
115 | //int steps = 65536 * 1024;
116 | //int[] array = new int[1024 * 1024 * 1];
117 |
118 | //var e = Utils.Measure(() => c.TestK(steps, array));
119 | //e = e * 1000;
120 | //Console.WriteLine((double)e / (double)steps);
121 |
122 | //var n = new POGenerator().Generate();
123 |
124 | //RowsVsCols test = new RowsVsCols();
125 | //Utils.Measure(test.Cols);
126 | //Console.ReadKey();
127 | }
128 | }
129 | }
130 |
131 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/AOSvsSOA.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.InteropServices;
4 | using System.Text;
5 |
6 | namespace DoDSamples
7 | {
8 | public class AOSvsSOA
9 | {
10 | //
11 | // This is a Data Oriented Design test that will show how
12 | // Struct of arrays has a much better Data Access characteristics and data locality.
13 | //
14 | // SOA [V0,V0,V0,V1,V1,V1]
15 | // AOS [V0,V1,V0,V1,V0,V1]
16 | //
17 | // For AOS for Structs or Classes we will have an 80 pad between which means that we will update each cache line
18 | // to increment the v0 value:
19 | // <0x281AF76B740> 80 80
20 | // <0x281AF76B790> 80 80
21 | // <0x281AF76B7E0> 80 80
22 | //
23 | // For SOA we will update each array value and reuse the same cache line:
24 | // Int32[] <0x216493DB6B8> 32 792 32 792
25 | // Int32[] <0x216493E36E8> 32 792 32 792
26 | // Int32[] <0x216493EB718> 32 792 32 792
27 | //
28 | // SOA is better in general for partial object updates while AOS is good when we want to contantly update entire
29 | // objects wich is almost never :)
30 | //
31 | public void TestAOS()
32 | {
33 | int steps = 1024 * 1024;
34 | int soaSize = 1024 * 8;
35 |
36 | SimpleStruct[] arrayOfStructs = new SimpleStruct[soaSize];
37 |
38 | for (int i = 0; i < arrayOfStructs.Length; i++)
39 | arrayOfStructs[i] = new SimpleStruct();
40 |
41 | for (int s = 0; s < steps; s++)
42 | {
43 | for (int i = 0; i < soaSize; i++)
44 | {
45 | arrayOfStructs[i].v0++;
46 | }
47 | }
48 | }
49 |
50 | public void TestSOA()
51 | {
52 | int steps = 1024 * 1024;
53 | int soaSize = 1024 * 8;
54 |
55 | SOAStruct soa = new SOAStruct(soaSize);
56 |
57 | for (int s = 0; s < steps; s++)
58 | {
59 | for (int i = 0; i < soaSize; i++)
60 | {
61 | soa.v0[i]++;
62 | }
63 | }
64 | }
65 | }
66 |
67 | class SOAStruct
68 | {
69 | public int[] v0;
70 | public int[] v1;
71 | public int[] v2;
72 | public int[] v3;
73 | public int[] v4;
74 | public int[] v5;
75 | public int[] v6;
76 | public int[] v7;
77 | public int[] v8;
78 | public int[] v9;
79 | public int[] v10;
80 | public int[] v11;
81 | public int[] v12;
82 | public int[] v13;
83 | public int[] v14;
84 | public int[] v15;
85 |
86 | public SOAStruct(int n)
87 | {
88 | v0 = new int[n];
89 | v1 = new int[n];
90 | v2 = new int[n];
91 | v3 = new int[n];
92 | v4 = new int[n];
93 | v5 = new int[n];
94 | v6 = new int[n];
95 | v7 = new int[n];
96 | v8 = new int[n];
97 | v9 = new int[n];
98 | v10 = new int[n];
99 | v11 = new int[n];
100 | v12 = new int[n];
101 | v13 = new int[n];
102 | v14 = new int[n];
103 | v15 = new int[n];
104 | }
105 |
106 | }
107 |
108 | class SimpleStruct
109 | {
110 | public int v0;
111 | public int v1;
112 | public int v2;
113 | public int v3;
114 | public int v4;
115 | public int v5;
116 | public int v6;
117 | public int v7;
118 | public int v8;
119 | public int v9;
120 | public int v10;
121 | public int v11;
122 | public int v12;
123 | public int v13;
124 | public int v14;
125 | public int v15;
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/ArrayEnumerableByRef.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DoDSamples
6 | {
7 | public readonly struct ArrayEnumerableByRef
8 | {
9 | private readonly T[] _target;
10 |
11 | public ArrayEnumerableByRef(T[] target) => _target = target;
12 |
13 | public Enumerator GetEnumerator() => new Enumerator(_target);
14 |
15 | public struct Enumerator
16 | {
17 | private readonly T[] _target;
18 |
19 | private int _index;
20 |
21 | public Enumerator(T[] target)
22 | {
23 | _target = target;
24 | _index = -1;
25 | }
26 |
27 | public readonly ref T Current
28 | {
29 | get
30 | {
31 | if (_target is null || _index < 0 || _index > _target.Length)
32 | {
33 | throw new InvalidOperationException();
34 | }
35 | return ref _target[_index];
36 | }
37 | }
38 |
39 | public bool MoveNext() => ++_index < _target.Length;
40 |
41 | public void Reset() => _index = -1;
42 | }
43 | }
44 |
45 | public static class ArrayExtensions
46 | {
47 | public static ArrayEnumerableByRef ToEnumerableByRef(this T[] array) => new ArrayEnumerableByRef(array);
48 | public static ArrayEnumerableByRef ToEnumerableByRef(this List list) => new ArrayEnumerableByRef(list.ToArray());
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/Benchmarks/InstructionAndDataDependency.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using BenchmarkDotNet.Order;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | namespace DoDSamples
8 | {
9 | [Orderer(SummaryOrderPolicy.SlowestToFastest, MethodOrderPolicy.Declared)]
10 | public class InstructionAndDataDependency
11 | {
12 |
13 | //[Benchmark]
14 | //public void InsDependency()
15 | //{
16 | // InstructionLevelDependency.TestDependency();
17 | //}
18 |
19 | //[Benchmark]
20 | //public void InsIndependency()
21 | //{
22 | // InstructionLevelDependency.TestIndependency();
23 | //}
24 |
25 | [Benchmark]
26 | public void InsIndependencySumUnroll()
27 | {
28 | InstructionLevelDependency.TestIndependencyUnrolledSum();
29 | }
30 |
31 | [Benchmark]
32 | public void InsDependencySumUnroll()
33 | {
34 | InstructionLevelDependency.TestDependencyUnrolledSum();
35 | }
36 |
37 | [Benchmark]
38 | public void InsDependencySum()
39 | {
40 | InstructionLevelDependency.TestSum();
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/Benchmarks/OOPvsDoDParsers.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using BenchmarkDotNet.Configs;
3 | using BenchmarkDotNet.Order;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Runtime.Intrinsics;
8 | using System.Runtime.Intrinsics.X86;
9 | using System.Text;
10 |
11 | namespace DoDSamples.Samples
12 | {
13 |
14 | [Orderer(SummaryOrderPolicy.SlowestToFastest, MethodOrderPolicy.Declared)]
15 | public class OOPvsDoDParsersToLower
16 | {
17 | [Params(100)]
18 | public int Samples = 1;
19 |
20 | private string[] lines = null;
21 |
22 | [GlobalSetup(Targets = new[]
23 | {
24 | nameof(ToLower),
25 | nameof(ToLowerASCIIInPlace_SIMD)
26 | })]
27 |
28 | public void GlobalSetup()
29 | {
30 | lines = File.ReadAllLines(@"C:\Users\Y700-17\Desktop\DataOrientedDesign\DoDSamples\DoDSamples\Samples\POParser\Sample.po");
31 | }
32 |
33 | [Benchmark]
34 | public void ToLowerASCIIInPlace_SIMD()
35 | {
36 | DoDPOParser_v5 parser = new DoDPOParser_v5();
37 | var dodLines_v5 = parser.Parse(lines, out var index);
38 |
39 | for (int s = 0; s < Samples; s++)
40 | {
41 | ToLowerASCIIInPlace_SIMD(dodLines_v5.AllNotes.ToString());
42 | }
43 | }
44 |
45 | [Benchmark]
46 | public void ToLower()
47 | {
48 | DoDPOParser_v5 parser = new DoDPOParser_v5();
49 | var dodLines_v5 = parser.Parse(lines, out var index);
50 |
51 | for (int s = 0; s < Samples; s++)
52 | {
53 | dodLines_v5.AllNotes.ToString().ToLower();
54 | }
55 | }
56 |
57 | public static unsafe void ToLowerASCIIInPlace_SIMD(string text)
58 | {
59 | const int upperIntOffset = 2097184;
60 | const int upperCharOffset = 32;
61 |
62 | Vector128 vresult = Vector128.Zero;
63 | Vector128 add = Vector128.Create(upperIntOffset);
64 |
65 | var len = text.Length;
66 |
67 | fixed (char* pSource = text)
68 | {
69 | int i = 0;
70 | int lastBlockIndex = len - (len % 8);
71 |
72 | while (i < lastBlockIndex)
73 | {
74 | int* c = (int*)(pSource + i);
75 |
76 | vresult = Sse2.LoadVector128(c);
77 | vresult = Sse2.Or(vresult, add);
78 |
79 | Sse2.Store(c, vresult);
80 |
81 | i += 8;
82 | }
83 |
84 | while (i < len)
85 | {
86 | char* c = (char*)(pSource + i);
87 | *c = (Char)(*c | upperCharOffset);
88 |
89 | i += 1;
90 | }
91 | }
92 | }
93 |
94 | }
95 |
96 |
97 | [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
98 | [CategoriesColumn]
99 | [Orderer(SummaryOrderPolicy.SlowestToFastest, MethodOrderPolicy.Declared)]
100 | public class OOPvsDoDParsers
101 | {
102 | [Params(100)]
103 | public int Samples = 1;
104 |
105 | private string[] lines = null;
106 | private string text = null;
107 |
108 | [GlobalSetup(Targets = new[]
109 | {
110 | //nameof(DoD_Parser_ListOfStructs),
111 | nameof(DoD_Parser_ArrayOfStructs),
112 | //nameof(DoD_Parser_ListOfStructs_Split),
113 | nameof(DoD_Parser_ArrayOfStructs_Split),
114 | nameof(DoD_Parser_ArrayOfStructs_HotColdSplit),
115 | nameof(DoD_Parser_StructOfArrays),
116 | nameof(DoD_Parser_StructOfArrays_SIMD),
117 | nameof(OOP_Parser_StateMachine),
118 |
119 | })]
120 |
121 | public void GlobalSetup()
122 | {
123 | lines = File.ReadAllLines(@"C:\Users\Y700-17\Desktop\DataOrientedDesign\DoDSamples\DoDSamples\Samples\POParser\Sample.po");
124 | }
125 |
126 | [GlobalSetup(Targets = new[] { nameof(OOP_Parser_Regex) })]
127 | public void GlobalSetupA()
128 | {
129 | text = File.ReadAllText(@"C:\Users\Y700-17\Desktop\DataOrientedDesign\DoDSamples\DoDSamples\Samples\POParser\Sample.po");
130 | }
131 |
132 | [BenchmarkCategory("OOP")]
133 | [Benchmark(Baseline = true)]
134 | public void OOP_Parser_Regex()
135 | {
136 | POParser parser = new POParser();
137 | var lines_v0 = parser.Parse(text);
138 |
139 | for (int s = 0; s < Samples; s++)
140 | {
141 | double sum = 0;
142 | foreach (var line in lines_v0)
143 | {
144 | sum += line.Amount;
145 | }
146 | }
147 | }
148 |
149 | [BenchmarkCategory("OOP")]
150 | [Benchmark]
151 | public void OOP_Parser_StateMachine()
152 | {
153 | POParser_Fast parser = new POParser_Fast();
154 | var lines_v0 = parser.Parse(lines);
155 |
156 | for (int s = 0; s < Samples; s++)
157 | {
158 | double sum = 0;
159 | foreach (var line in lines_v0)
160 | {
161 | sum += line.Amount;
162 | }
163 | }
164 | }
165 |
166 | //[BenchmarkCategory("DoD")]
167 | //[Benchmark]
168 | //public void DoD_Parser_ListOfStructs()
169 | //{
170 | // DoDPOParser_v1 parser = new DoDPOParser_v1();
171 | // var lines_v1 = parser.Parse(lines);
172 |
173 | // for (int s = 0; s < Samples; s++)
174 | // {
175 | // double sum = 0;
176 |
177 | // foreach (var line in lines_v1)
178 | // {
179 | // sum += line.Amount;
180 | // }
181 | // }
182 | //}
183 |
184 | [BenchmarkCategory("DoD")]
185 | [Benchmark(Baseline = true)]
186 | public void DoD_Parser_ArrayOfStructs()
187 | {
188 | DoDPOParser_v1a parser = new DoDPOParser_v1a();
189 | var lines_v1 = parser.Parse(lines, out int index);
190 |
191 | for (int s = 0; s < Samples; s++)
192 | {
193 | double sum = 0;
194 |
195 | foreach (var line in lines_v1)
196 | {
197 | sum += line.Amount;
198 | }
199 | }
200 | }
201 |
202 | //[BenchmarkCategory("DoD")]
203 | //[Benchmark]
204 | //public void DoD_Parser_ListOfStructs_Split()
205 | //{
206 | // DoDPOParser_v2 parser = new DoDPOParser_v2();
207 | // var lines_v2 = parser.Parse(lines);
208 |
209 | // for (int s = 0; s < Samples; s++)
210 | // {
211 | // double sum = 0;
212 |
213 | // foreach (var line in lines_v2)
214 | // {
215 | // sum += line.Amount;
216 | // }
217 | // }
218 | //}
219 |
220 | [BenchmarkCategory("DoD")]
221 | [Benchmark]
222 | public void DoD_Parser_ArrayOfStructs_Split()
223 | {
224 | DoDPOParser_v2a parser = new DoDPOParser_v2a();
225 | var lines_v2 = parser.Parse(lines, out int index);
226 |
227 | for (int s = 0; s < Samples; s++)
228 | {
229 | double sum = 0;
230 |
231 | foreach (var line in lines_v2)
232 | {
233 | sum += line.Amount;
234 | }
235 | }
236 | }
237 |
238 | [BenchmarkCategory("DoD")]
239 | [Benchmark]
240 | public void DoD_Parser_ArrayOfStructs_HotColdSplit()
241 | {
242 | DoDPOParser_v3 parser = new DoDPOParser_v3();
243 | var lines_v3 = parser.Parse(lines);
244 |
245 | for (int s = 0; s < Samples; s++)
246 | {
247 | double sum = 0;
248 |
249 | for (int i = 0; i < lines_v3.Count; i++)
250 | {
251 | sum += lines_v3[i].Amount;
252 | }
253 | }
254 | }
255 |
256 | [BenchmarkCategory("DoD")]
257 | [Benchmark]
258 | public void DoD_Parser_StructOfArrays()
259 | {
260 | DoDPOParser_v4 parser = new DoDPOParser_v4();
261 | var dodLines_v4 = parser.Parse(lines, out var index);
262 |
263 | for (int s = 0; s < Samples; s++)
264 | {
265 | double sum = 0;
266 | for (int i = 0; i < index; i++)
267 | {
268 | sum += dodLines_v4.Amount[i];
269 | }
270 | }
271 | }
272 |
273 | [BenchmarkCategory("DoD")]
274 | [Benchmark]
275 | public void DoD_Parser_StructOfArrays_SIMD()
276 | {
277 | DoDPOParser_v4 parser = new DoDPOParser_v4();
278 | var dodLines_v4 = parser.Parse(lines, out var index);
279 |
280 | for (int s = 0; s < Samples; s++)
281 | {
282 | double sum = SumAmount(dodLines_v4, index);
283 | }
284 | }
285 |
286 |
287 | public unsafe double SumAmount(DoDPOLines_v4 source, int len)
288 | {
289 | double result;
290 |
291 | fixed (double* pSource = source.Amount)
292 | {
293 | Vector128 vresult = Vector128.Zero;
294 |
295 | int i = 0;
296 | int lastBlockIndex = len - (len % 2);
297 |
298 | while (i < lastBlockIndex)
299 | {
300 | vresult = Sse2.Add(vresult, Sse2.LoadVector128(pSource + i));
301 | i += 2;
302 | }
303 |
304 | vresult = Ssse3.HorizontalAdd(vresult, vresult);
305 | result = vresult.ToScalar();
306 |
307 | while (i < len)
308 | {
309 | result += pSource[i];
310 | i += 1;
311 | }
312 | }
313 |
314 | return result;
315 | }
316 | }
317 | }
318 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/Benchmarks/RefListvsList.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace DoDSamples.Samples.Benchmarks
7 | {
8 |
9 | //public class RefListVSList
10 | //{
11 | // private List list;
12 | // private RefList refList;
13 | // private const int size = 1_000_000;
14 |
15 | // [IterationSetup(Target = nameof(List))]
16 | // public void SetUpList()
17 | // {
18 | // list = new List(size);
19 | // for (int i = 0; i < size; i++)
20 | // {
21 | // list.Add(new POLine_v1() { ID = i });
22 | // }
23 | // }
24 |
25 | // [IterationSetup(Target = nameof(RefList))]
26 | // public void SetUpRefList()
27 | // {
28 | // refList = new RefList(size);
29 | // for (int i = 0; i < size; i++)
30 | // {
31 | // refList.Add(new POLine_v1() { ID = i });
32 | // }
33 | // }
34 |
35 | // [Benchmark]
36 | // public void List()
37 | // {
38 | // double sum = 0;
39 |
40 | // foreach(var item in list)
41 | // {
42 | // sum += item.Amount;
43 | // }
44 | // }
45 |
46 | // [Benchmark]
47 | // public void RefList()
48 | // {
49 | // double sum = 0;
50 |
51 | // foreach (var item in refList)
52 | // {
53 | // sum += item.Amount;
54 | // }
55 | // }
56 | //}
57 | }
58 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/Benchmarks/RowsVsCols.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace DoDSamples
7 | {
8 |
9 | //
10 | // This example demonstrates the performance
11 | // of Row vs Col access using a flat array.
12 | // It also shows how much performance can improve if we simply
13 | // use our cache line to the full extent.
14 | //
15 | // It shows how proper datta access patterns are important,
16 | // even in a single threaded enviroment.
17 | //
18 | public class RowsVsCols
19 | {
20 | private const int rows = 10_000;
21 | private const int cols = 10_000;
22 | private int[] array = new int[rows * cols];
23 |
24 | [IterationSetup]
25 | public void SetUp()
26 | {
27 | array = new int[rows * cols];
28 | }
29 |
30 | [Benchmark]
31 | public void Rows()
32 | {
33 | for(int i = 0; i < cols; i++)
34 | {
35 | for(int j = 0; j < rows; j++)
36 | {
37 | array[(i * cols) + j]++;
38 | }
39 | }
40 | }
41 |
42 | [Benchmark]
43 | public void Cols()
44 | {
45 | for (int i = 0; i < rows; i++)
46 | {
47 | for (int j = 0; j < cols; j++)
48 | {
49 | array[(j * cols) + i]++;
50 | }
51 | }
52 | }
53 |
54 | [Benchmark]
55 | public void ColsStride()
56 | {
57 | for (int i = 0; i < rows; i += 8)
58 | {
59 | for (int j = 0; j < cols; j++)
60 | {
61 | array[(j * cols) + i + 0]++;
62 | array[(j * cols) + i + 1]++;
63 | array[(j * cols) + i + 2]++;
64 | array[(j * cols) + i + 3]++;
65 | array[(j * cols) + i + 4]++;
66 | array[(j * cols) + i + 5]++;
67 | array[(j * cols) + i + 6]++;
68 | array[(j * cols) + i + 7]++;
69 | //Console.WriteLine((j * cols) + i);
70 | }
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/BitOperations.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Diagnostics.Runtime.Utilities;
2 | using Microsoft.Diagnostics.Tracing.Parsers.Kernel;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Runtime.Intrinsics;
6 | using System.Runtime.Intrinsics.X86;
7 | using System.Text;
8 |
9 | namespace DoDSamples.Samples
10 | {
11 | public class BitOperations
12 | {
13 |
14 | //
15 | // Branch Elimination Example: lets count even numbers
16 | //
17 |
18 |
19 |
20 | public static int CountEven(int[] numbers)
21 | {
22 | int counter = 0;
23 | for(int i = 0; i < numbers.Length; i++)
24 | {
25 | if(numbers[i] % 2 == 0)
26 | {
27 | counter++;
28 | }
29 | }
30 |
31 | return counter;
32 | }
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | public static int CountEvenBranchFree(int[] numbers)
41 | {
42 | int counter = 0;
43 | for (int i = 0; i < numbers.Length; i++)
44 | {
45 | var add = numbers[i] & 1;
46 | counter += (1 - add);
47 | }
48 |
49 | return counter;
50 | }
51 |
52 |
53 |
54 |
55 | public static int CountEvenBranchFreeBetter(int[] numbers)
56 | {
57 | int counter = 0;
58 | for (int i = 0; i < numbers.Length; i++)
59 | {
60 | var odd = numbers[i] & 1;
61 | counter += odd;
62 | }
63 |
64 | // Take all odd numbers and substract them from the set
65 | // leaving only even numbers
66 | return numbers.Length - counter;
67 | }
68 |
69 |
70 |
71 |
72 |
73 | public static unsafe int CountEvenSIMD(int[] numbers)
74 | {
75 | int counter = 0;
76 | int len = numbers.Length;
77 |
78 | fixed (int* num = numbers)
79 | {
80 | Vector128 vresult = Vector128.Zero;
81 | Vector128 ones = Vector128.Create(1);
82 |
83 | int i = 0;
84 | int lastBlockIndex = len - (len % 4);
85 |
86 | while (i < lastBlockIndex)
87 | {
88 | var vec = Sse2.LoadVector128(num + i);
89 | var odds = Sse2.And(vec, ones);
90 | vresult = Sse2.Add(vresult, odds);
91 |
92 | i += 4;
93 | }
94 |
95 | vresult = Ssse3.HorizontalAdd(vresult, vresult);
96 | vresult = Ssse3.HorizontalAdd(vresult, vresult);
97 |
98 | counter = vresult.ToScalar();
99 |
100 | while (i < len)
101 | {
102 | var odd = numbers[i] & 1;
103 | counter += odd;
104 |
105 | i += 1;
106 | }
107 | }
108 |
109 | return numbers.Length - counter;
110 | }
111 |
112 | public static int CountChar(string text, char needle)
113 | {
114 | int count = 0;
115 |
116 | foreach(var c in text)
117 | {
118 | if (c == needle)
119 | count++;
120 | }
121 |
122 | return count;
123 | }
124 |
125 |
126 |
127 |
128 |
129 |
130 | private static int[] jump_table = new int[256];
131 |
132 | public static void InitJumpTable(char needle)
133 | {
134 | int cIdx = (byte)needle;
135 |
136 | for(int i = 0; i < jump_table.Length; i++)
137 | {
138 | jump_table[i] = 0;
139 | if (i == cIdx)
140 | {
141 | jump_table[i] = 1;
142 | }
143 | }
144 | }
145 |
146 | public static int CountCharJumpTable(string text, char needle)
147 | {
148 | int count = 0;
149 |
150 | foreach (var c in text)
151 | {
152 | count += jump_table[(byte)c];
153 | }
154 |
155 | return count;
156 | }
157 |
158 | public static int CountCharWORD(string text, char needle)
159 | {
160 | int count = 0;
161 | byte charToFind = (byte)needle;
162 | byte before = (byte)(charToFind - 1);
163 | byte after = (byte)(charToFind + 1);
164 |
165 | unsafe
166 | {
167 | fixed (char* ch = text)
168 | {
169 | int len = text.Length;
170 |
171 | int i = 0;
172 | int lastBlockIndex = len - (len % 4);
173 |
174 | while (i < lastBlockIndex)
175 | {
176 | ulong* p = (ulong*)(ch + i);
177 | var result = (int)CountBetween(*p, before, after);
178 | count += result;
179 |
180 | i += 4;
181 | }
182 |
183 | while (i < len)
184 | {
185 | char* c = (char*)(ch + i);
186 | if (*c == charToFind)
187 | {
188 | count++;
189 | }
190 | i += 1;
191 | }
192 |
193 | return count - len;
194 | }
195 | }
196 | }
197 |
198 | public static int CountWhitespaceWORDLess(string text)
199 | {
200 | int count = 0;
201 | byte charToFind = (byte)' ';
202 | byte after = (byte)(charToFind + 1);
203 |
204 | unsafe
205 | {
206 | fixed (char* ch = text)
207 | {
208 | int len = text.Length;
209 |
210 | int i = 0;
211 | int lastBlockIndex = len - (len % 4);
212 |
213 | while (i < lastBlockIndex)
214 | {
215 | ulong* p = (ulong*)(ch + i);
216 | var result = (int)CountLess(*p, after);
217 | count += result;
218 |
219 | i += 4;
220 | }
221 |
222 | while (i < len)
223 | {
224 | char* c = (char*)(ch + i);
225 | if (*c == charToFind)
226 | {
227 | count++;
228 | }
229 | i += 1;
230 | }
231 |
232 | return count - len;
233 | }
234 | }
235 | }
236 |
237 | public static int CountCharWORDCompact(string text, char needle)
238 | {
239 | int count = 0;
240 | byte charToFind = (byte)needle;
241 | byte before = (byte)(charToFind - 1);
242 | byte after = (byte)(charToFind + 1);
243 |
244 | unsafe
245 | {
246 | fixed (char* ch = text)
247 | {
248 | int len = text.Length;
249 |
250 | int i = 0;
251 | int lastBlockIndex = len - (len % 4);
252 |
253 | while (i < lastBlockIndex)
254 | {
255 | ulong* p = (ulong*)(ch + i);
256 |
257 | var has = HasValue(*p, charToFind);
258 | if (has > 0)
259 | {
260 | var result = CountBetween(*p, before, after);
261 | count += (int)result;
262 | }
263 |
264 | i += 4;
265 | }
266 |
267 | while (i < len)
268 | {
269 | char* c = (char*)(ch + i);
270 | if (*c == charToFind)
271 | {
272 | count++;
273 | }
274 | i += 1;
275 | }
276 |
277 | return count;
278 | }
279 | }
280 | }
281 |
282 | public static int CountWhitespaceWORDCompactLess(string text)
283 | {
284 | int count = 0;
285 | byte charToFind = (byte)' ';
286 | byte after = (byte)(charToFind + 1);
287 |
288 | unsafe
289 | {
290 | fixed (char* ch = text)
291 | {
292 | int len = text.Length;
293 |
294 | int i = 0;
295 | int lastBlockIndex = len - (len % 4);
296 |
297 | while (i < lastBlockIndex)
298 | {
299 | ulong* p = (ulong*)(ch + i);
300 |
301 | var has = HasValue(*p, charToFind);
302 | if (has > 0)
303 | {
304 | var result = CountLess(*p, after);
305 | count += (int)result;
306 | }
307 |
308 | i += 4;
309 | }
310 |
311 | while (i < len)
312 | {
313 | char* c = (char*)(ch + i);
314 | if (*c == charToFind)
315 | {
316 | count++;
317 | }
318 | i += 1;
319 | }
320 |
321 | return count;
322 | }
323 | }
324 | }
325 |
326 | //
327 | // Bit Twindling Hacks:
328 | // https://graphics.stanford.edu/~seander/bithacks.html
329 | //
330 | public static ulong HasZero(ulong v)
331 | {
332 | return (((v) - 0x0101010101010101UL) & ~(v) & 0x8080808080808080UL);
333 | }
334 |
335 | public static ulong HasValue(ulong x, byte n)
336 | {
337 | return (HasZero((x) ^ (~0UL / 255 * (n))));
338 | }
339 |
340 | public static ulong HasLess(ulong x, byte n)
341 | {
342 | return (((x) - ~0UL / 255 * (n)) & ~(x) & ~0UL / 255 * 128);
343 | }
344 |
345 | public static ulong CountLess(ulong x, byte n)
346 | {
347 | return (((~0UL / 255 * (127 + ((ulong)n)) - ((x) & ~0UL / 255 * 127)) & ~(x) & ~0UL / 255 * 128) / 128 % 255);
348 | }
349 |
350 | public static ulong HasBetween(ulong x, byte m, byte n)
351 | {
352 | return ((~0UL / 255 * (127 + ((ulong)n))
353 | - ((x) & ~0UL / 255 * 127) &
354 | ~(x) & ((x) & ~0UL / 255 * 127) +
355 | ~0UL / 255 * (127 - ((ulong)m))) & ~0UL / 255 * 128);
356 | }
357 |
358 | public static ulong CountBetween(ulong x, byte m, byte n)
359 | {
360 | return HasBetween(x, m, n) / 128 % 255;
361 | }
362 |
363 |
364 |
365 | }
366 | }
367 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/BlockList.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.CompilerServices;
4 | using System.Text;
5 |
6 | namespace DoDSamples
7 | {
8 | public class BlockList
9 | {
10 | private ListBlock[] blocks = new ListBlock[32];
11 | private int blockIndex = 0;
12 | private int blockSize = 512;
13 | private ListBlock mainBlock = null;
14 |
15 | public BlockList()
16 | {
17 | mainBlock = new ListBlock(blockSize);
18 | blocks[blockIndex++] = mainBlock;
19 | }
20 |
21 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
22 | public void Add(T value)
23 | {
24 | var blockFull = mainBlock.Add(value);
25 | //
26 | // Add another block
27 | //
28 | if (blockFull)
29 | {
30 | mainBlock = new ListBlock(blockSize);
31 | blocks[blockIndex++] = mainBlock;
32 | }
33 | }
34 |
35 | public T Get(int index)
36 | {
37 | var blockId = index / blockSize;
38 | return blocks[blockId].Get(index - (blockId * blockSize));
39 | }
40 |
41 | public ListBlock GetBlock(int index, out int indexInBlock)
42 | {
43 | var blockId = index / blockSize;
44 | indexInBlock = index - (blockId * blockSize);
45 | return blocks[blockId];
46 | }
47 |
48 | public void Set(int index, T value)
49 | {
50 | var blockId = index / blockSize;
51 | blocks[blockId].Set(index - (blockId * blockSize), value);
52 | }
53 |
54 | public T this[int index]
55 | {
56 | get { return Get(index); }
57 | set { Set(index, value); }
58 | }
59 |
60 | public class ListBlock
61 | {
62 | public ListBlock(int blockSize)
63 | {
64 | array = new T[blockSize];
65 | }
66 |
67 | public T Get(int index)
68 | {
69 | return array[index];
70 | }
71 |
72 | public void Set(int index, T value)
73 | {
74 | array[index] = value;
75 | }
76 |
77 | private T[] array;
78 | private int index = 0;
79 |
80 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
81 | public bool Add(T value)
82 | {
83 | array[index++] = value;
84 | return (index >= array.Length);
85 | }
86 | }
87 |
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/CacheSize.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DoDSamples
6 | {
7 | public class CacheSize
8 | {
9 | //
10 | // This class will test the cache line sizes for various levels
11 | // The idea is simple: Move through the array loading a new cache line on every step
12 | // if we exceed the size of the array we start from the begining and continue.
13 | // We do this for a set amount of steps and mesure the assigment time, if we move to the
14 | // next cache level there will be a significant slowdown.
15 | //
16 | // How to Perform the test:
17 | //
18 | // int steps = 65536 * 1024;
19 | // int[] array = new int[1024 * 1024 * 1];
20 | //
21 | // var e = Utils.Measure(() => c.TestK(steps, array));
22 | // e = e* 1000; //Scale the time
23 | // Console.WriteLine((double) e / (double) steps);
24 | //
25 | public static void TestK(int steps, int[] array)
26 | {
27 | int lengthMod = array.Length - 1;
28 |
29 | for (int i = 0; i < steps; i++)
30 | {
31 | array[(i * 16) & lengthMod]++;
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/InstructionLevelDependency.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.Intrinsics;
5 | using System.Runtime.Intrinsics.X86;
6 | using System.Text;
7 |
8 | namespace DoDSamples
9 | {
10 | #region desc
11 | //
12 | // Instruction Level Dependency:
13 | // Good compilers will do it's best to break dependency chains
14 | // but sometimes it's just impossible and it's up to the user to break non trival chains.
15 | //
16 | #endregion
17 |
18 | public class InstructionLevelDependency
19 | {
20 | public static int steps = 128 * 1024 * 1024;
21 | public static readonly int i32Bits = sizeof(int) * 8 - 1;
22 |
23 | public static int TestDependency()
24 | {
25 | int a = 0;
26 |
27 | for (int i = 0; i < steps; i++)
28 | {
29 | a++;
30 | a++;
31 | a++;
32 | a++;
33 | }
34 |
35 | return a;
36 | }
37 |
38 | public static int TestIndependency()
39 | {
40 | int a = 0, b = 0, c = 0, d = 0;
41 |
42 | for (int i = 0; i < steps; i++)
43 | {
44 | a++;
45 | b++;
46 | c++;
47 | d++;
48 | }
49 |
50 | return a + b + c + d;
51 | }
52 |
53 | public static void TestSum()
54 | {
55 | double[] x = new double[steps];
56 | double sum = 0;
57 |
58 | for (int i = 0; i < steps; i++)
59 | {
60 | sum += x[i];
61 | }
62 | }
63 |
64 | public static void TestDependencyUnrolledSum()
65 | {
66 | double[] x = new double[steps];
67 | double sum = 0;
68 |
69 | int i = 0;
70 | for (; i < steps; i += 4)
71 | {
72 | sum += x[i];
73 | sum += x[i + 1];
74 | sum += x[i + 2];
75 | sum += x[i + 3];
76 | }
77 | // Sum residuals
78 | for (; i < steps; i++)
79 | {
80 | sum += x[i];
81 | }
82 | }
83 |
84 | public static void TestIndependencyUnrolledSum()
85 | {
86 | int steps = 64 * 1024 * 1024;
87 |
88 | double[] x = new double[steps];
89 | double sum = 0;
90 | double sa = 0, sb = 0, sc = 0, sd = 0;
91 |
92 | int i = 0;
93 | for (; i < steps; i += 4)
94 | {
95 | sa += x[i];
96 | sb += x[i + 1];
97 | sc += x[i + 2];
98 | sd += x[i + 3];
99 | }
100 |
101 | // Sum residuals
102 | for (; i < steps; i++)
103 | {
104 | sum += x[i];
105 | }
106 |
107 | sum = sa + sb + sc + sd;
108 | }
109 |
110 | public static void TestIndependencyUnrolledSum2()
111 | {
112 | int steps = 64 * 1024 * 1024;
113 |
114 | double[] x = new double[steps];
115 | double sum = 0;
116 | double sa = 0, sb = 0, sc = 0, sd = 0;
117 |
118 | int i = 0;
119 | for (; i < steps; i += 4)
120 | {
121 | sa += x[i];
122 | sb += x[i + 1];
123 | sc += x[i + 2];
124 | sd += x[i + 3];
125 | }
126 |
127 | // Sum residuals
128 | for (; i < steps; i++)
129 | {
130 | sum += x[i];
131 | }
132 |
133 | sum = (sa + sb) + (sc + sd);
134 | }
135 |
136 | public static void TestTrueDependence(int[] x)
137 | {
138 | var min = 0;
139 |
140 | for (int i = 0; i < x.Length; i++)
141 | {
142 | min = Math.Min(min, x[i]);
143 | //min = MinBranch(min, x[i]);
144 | }
145 | }
146 |
147 | public static void TestTrueIndependence(int[] x)
148 | {
149 | var min = 0;
150 | var m1 = 0;
151 | var m2 = 0;
152 | var m3 = 0;
153 | var m4 = 0;
154 |
155 | for (int i = 0; i < x.Length; i += 4)
156 | {
157 | m1 = MinBranchFree(m1, x[i]);
158 | m2 = MinBranchFree(m2, x[i + 1]);
159 | m3 = MinBranchFree(m3, x[i + 2]);
160 | m4 = MinBranchFree(m4, x[i + 3]);
161 | }
162 |
163 | min = MinBranchFree(m1, MinBranchFree(m2, MinBranchFree(m3, m4)));
164 | }
165 |
166 | public static void TestTrueIndependenceAVX(int[] x)
167 | {
168 | var min = 0;
169 | var m1 = 0;
170 | var m2 = 0;
171 | var m3 = 0;
172 | var m4 = 0;
173 |
174 | for (int i = 0; i < x.Length; i += 4)
175 | {
176 | m1 = AVXMin(m1, x[i]);
177 | m2 = AVXMin(m2, x[i + 1]);
178 | m3 = AVXMin(m3, x[i + 2]);
179 | m4 = AVXMin(m4, x[i + 3]);
180 | }
181 |
182 | min = AVXMin(m1, AVXMin(m2, AVXMin(m3, m4)));
183 | }
184 |
185 | public static int TestTrueIndependenceAVXVec(int[] x)
186 | {
187 | return AVXVecMin(x);
188 | }
189 |
190 | public static int TestTrueIndependenceAVXVecIndependant(int[] x)
191 | {
192 | return AVXVecMinIndependent(x);
193 | }
194 |
195 | public static void TestTrueDependenceBranchFree(int[] x)
196 | {
197 | int min = int.MaxValue, inc = 0;
198 | for (int i = 0; i < x.Length; i++)
199 | {
200 | inc = IsMinBranchFree(min, x[i]);
201 | var delta = min - x[i];
202 | min = min - (delta * inc);
203 | }
204 | }
205 |
206 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
207 | public static int IsMinBranchFree(int x, int y)
208 | {
209 | var v = x - y;
210 | return (int)((1 ^ ((uint)v >> (31))));
211 | }
212 |
213 |
214 | public static void TestTrueIndependenceDelta(int[] x)
215 | {
216 | var max = int.MaxValue;
217 | int[] m = new int[4] { max, max, max, max };
218 | var inc = 0;
219 | for (int i = 0; i < x.Length; i += 4)
220 | {
221 | for (int w = 0; w < m.Length; w++)
222 | {
223 | inc = IsMinBranchFree(m[w], x[i + w]);
224 | var delta = m[w] - x[i + w];
225 | m[w] = m[w] - (delta * inc);
226 | }
227 | }
228 | // todo: residuals + min(m[0],m[1],m[2],m[3])
229 | }
230 |
231 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
232 | public static int MinBranchFree(int x, int y)
233 | {
234 | return y + ((x - y) & ((x - y) >> (31)));
235 | }
236 |
237 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
238 | public static int AVXMin(int x, int y)
239 | {
240 | var v1 = Vector128.CreateScalarUnsafe(x);
241 | var v2 = Vector128.CreateScalarUnsafe(y);
242 | return Avx.Min(v1, v2).ToScalar();
243 | }
244 |
245 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
246 | public static unsafe int AVXVecMin(int[] x)
247 | {
248 | int len = x.Length;
249 | var min = Vector128.Create(int.MaxValue);
250 | fixed (int* pSource = x)
251 | {
252 | int i = 0;
253 | int lastBlockIndex = len - (len % 4);
254 |
255 | while (i < lastBlockIndex) {
256 | min = Avx.Min(min, Avx.LoadVector128(pSource + i));
257 | i += 4;
258 | }
259 | var minValue = min.ToScalar();
260 | while (i < len) {
261 | minValue = MinBranchFree(minValue, pSource[i]);
262 | i += 1;
263 | }
264 | return minValue;
265 | }
266 | }
267 |
268 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
269 | public static unsafe int AVXVecMinIndependent(int[] x)
270 | {
271 | int len = x.Length;
272 | var min1 = Vector128.Create(int.MaxValue);
273 | var min2 = Vector128.Create(int.MaxValue);
274 |
275 | fixed (int* pSource = x)
276 | {
277 | int i = 0;
278 | int lastBlockIndex = len - (len % 8);
279 |
280 | while (i < lastBlockIndex)
281 | {
282 | min1 = Avx.Min(min1, Avx.LoadVector128(pSource + i));
283 | min2 = Avx.Min(min2, Avx.LoadVector128(pSource + i + 4));
284 |
285 | i += 8;
286 | }
287 | var minValue = min1.ToScalar() + min2.ToScalar();
288 | while (i < len)
289 | {
290 | minValue = MinBranchFree(minValue, pSource[i]);
291 | i += 1;
292 | }
293 | return minValue;
294 | }
295 | }
296 |
297 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
298 | public static int MinBranch(int x, int y)
299 | {
300 | return (x <= y) ? x : y;
301 | }
302 | }
303 | }
304 |
305 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/MemoryModelDeadlock.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 |
6 | namespace DoDSamples
7 | {
8 | public class MemoryModelDeadlock
9 | {
10 | public void Test()
11 | {
12 | bool isSignaled = false;
13 |
14 | Thread master = new Thread(() =>
15 | {
16 | Console.WriteLine($"{DateTime.UtcNow} [Thread:{Thread.CurrentThread.ManagedThreadId}] Waiting 1000ms and setting the Signal Variable");
17 | Thread.Sleep(1000);
18 |
19 | Console.WriteLine($"{DateTime.UtcNow} [Thread:{Thread.CurrentThread.ManagedThreadId}] Signal!");
20 | isSignaled = true;
21 | });
22 |
23 | master.Start();
24 |
25 | Thread slave = new Thread(() =>
26 | {
27 | while (isSignaled == false) { }
28 | Console.WriteLine($"{DateTime.UtcNow} [Thread:{Thread.CurrentThread.ManagedThreadId}] I Was Signaled");
29 |
30 | });
31 |
32 | slave.Start();
33 |
34 | //slave.Join();
35 | //master.Join();
36 | }
37 |
38 | SpinLock spinLock = new SpinLock();
39 |
40 | public void Spin()
41 | {
42 | bool taken = false;
43 | for (int i = 0; i < 1000; i++)
44 | {
45 | taken = false;
46 |
47 | spinLock.Enter(ref taken);
48 | {
49 | int d = 0;
50 | for (int k = 0; k < 1000000; k++)
51 | d++;
52 | }
53 | spinLock.Exit(true);
54 |
55 | if (taken == false)
56 | Console.WriteLine(taken);
57 | }
58 | }
59 |
60 | public void SpinLockTest()
61 | {
62 | Thread[] threads = new Thread[32];
63 | for(int i = 0; i < threads.Length; i++)
64 | {
65 | threads[i] = new Thread(() => Spin());
66 | }
67 |
68 | for (int i = 0; i < threads.Length; i++)
69 | {
70 | threads[i].Start();
71 | }
72 |
73 | for (int i = 0; i < threads.Length; i++)
74 | {
75 | threads[i].Join();
76 | }
77 |
78 | Console.WriteLine("[Done]");
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/POParser/DoDPOParser_v1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 |
6 | namespace DoDSamples.Samples
7 | {
8 | public struct POLine_v1
9 | {
10 | public int ID;
11 | public double Amount;
12 | public string Date;
13 | public string Time;
14 | public string Note;
15 | }
16 |
17 | public class DoDPOParser_v1
18 | {
19 |
20 | private enum State
21 | {
22 | ID,
23 | DateTime,
24 | Amount,
25 | Note
26 | }
27 |
28 | public List Parse(string path) => Parse(File.ReadAllLines(path));
29 |
30 | public List Parse(string[] lines)
31 | {
32 | List transactionLines = new List(1000);
33 | POLine_v1 poLine = new POLine_v1();
34 |
35 | State state = State.ID;
36 | foreach (var line in lines)
37 | {
38 | if (string.IsNullOrEmpty(line))
39 | {
40 | if (state >= State.Note)
41 | {
42 | transactionLines.Add(poLine);
43 | state = State.ID;
44 | }
45 |
46 | continue;
47 | }
48 | switch (state)
49 | {
50 | case State.ID:
51 | {
52 | poLine.ID = int.Parse(line);
53 |
54 | state++;
55 | break;
56 | }
57 | case State.DateTime:
58 | {
59 | var dt = line.Split('T');
60 | poLine.Date = dt[0];
61 | poLine.Time = dt[1];
62 |
63 | state++;
64 | break;
65 | }
66 | case State.Amount:
67 | {
68 | poLine.Amount = double.Parse(line);
69 |
70 | state++;
71 | break;
72 | }
73 | case State.Note:
74 | {
75 | poLine.Note += line;
76 |
77 | state++;
78 | break;
79 | }
80 | }
81 | }
82 |
83 | return transactionLines;
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/POParser/DoDPOParser_v1a.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 |
6 | namespace DoDSamples.Samples
7 | {
8 | public class DoDPOParser_v1a
9 | {
10 | private enum State
11 | {
12 | ID,
13 | DateTime,
14 | Amount,
15 | Note
16 | }
17 |
18 | public POLine_v1[] Parse(string path, out int index) => Parse(File.ReadAllLines(path), out index);
19 |
20 | public POLine_v1[] Parse(string[] lines, out int index)
21 | {
22 | index = 0;
23 |
24 | POLine_v1[] transactionLines = new POLine_v1[1000];
25 | POLine_v1 poLine = new POLine_v1();
26 |
27 | State state = State.ID;
28 | foreach (var line in lines)
29 | {
30 | if (string.IsNullOrEmpty(line))
31 | {
32 | if (state >= State.Note)
33 | {
34 | transactionLines[index] = poLine;
35 | state = State.ID;
36 | index++;
37 | }
38 |
39 | continue;
40 | }
41 | switch (state)
42 | {
43 | case State.ID:
44 | {
45 | poLine.ID = int.Parse(line);
46 |
47 | state++;
48 | break;
49 | }
50 | case State.DateTime:
51 | {
52 | var dt = line.Split('T');
53 | poLine.Date = dt[0];
54 | poLine.Time = dt[1];
55 |
56 | state++;
57 | break;
58 | }
59 | case State.Amount:
60 | {
61 | poLine.Amount = double.Parse(line);
62 |
63 | state++;
64 | break;
65 | }
66 | case State.Note:
67 | {
68 | poLine.Note += line;
69 |
70 | state++;
71 | break;
72 | }
73 | }
74 | }
75 |
76 | return transactionLines;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/POParser/DoDPOParser_v2.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Net.Http.Headers;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 |
8 | namespace DoDSamples.Samples
9 | {
10 |
11 | //
12 | // You might thing that this is better setting the pack but if you think about it, this data set breaks
13 | // aligment, and thus all potential gains will be nullified by missaligment.
14 | //
15 | //[StructLayout(LayoutKind.Sequential, Pack = 4)]
16 | public struct POLine_v2
17 | {
18 | public int ID;
19 | public double Amount;
20 | public PODateTime PODateTime;
21 | public string Note;
22 | }
23 |
24 | public struct PODateTime
25 | {
26 | public string Date;
27 | public string Time;
28 | }
29 |
30 |
31 | public class DoDPOParser_v2
32 | {
33 | private enum State
34 | {
35 | ID,
36 | DateTime,
37 | Amount,
38 | Note
39 | }
40 |
41 | public List Parse(string path) => Parse(File.ReadAllLines(path));
42 |
43 | public List Parse(string[] lines)
44 | {
45 | List transactionLines = new List(1000);
46 |
47 | POLine_v2 poLine = new POLine_v2();
48 |
49 | State state = State.ID;
50 | foreach (var line in lines)
51 | {
52 | if (string.IsNullOrEmpty(line))
53 | {
54 | if (state >= State.Note)
55 | {
56 | transactionLines.Add(poLine);
57 | state = State.ID;
58 | }
59 |
60 | continue;
61 | }
62 | switch (state)
63 | {
64 | case State.ID:
65 | {
66 | poLine.ID = int.Parse(line);
67 |
68 | state++;
69 | break;
70 | }
71 | case State.DateTime:
72 | {
73 | var dt = line.Split('T');
74 | poLine.PODateTime.Date = dt[0];
75 | poLine.PODateTime.Time = dt[1];
76 |
77 | state++;
78 | break;
79 | }
80 | case State.Amount:
81 | {
82 | poLine.Amount = double.Parse(line);
83 |
84 | state++;
85 | break;
86 | }
87 | case State.Note:
88 | {
89 | poLine.Note += line;
90 |
91 | state++;
92 | break;
93 | }
94 | }
95 | }
96 |
97 | return transactionLines;
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/POParser/DoDPOParser_v2a.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Net.Http.Headers;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 |
8 | namespace DoDSamples.Samples
9 | {
10 |
11 | public class DoDPOParser_v2a
12 | {
13 | private enum State
14 | {
15 | ID,
16 | DateTime,
17 | Amount,
18 | Note
19 | }
20 |
21 | public POLine_v2[] Parse(string path, out int index) => Parse(File.ReadAllLines(path), out index);
22 |
23 | public POLine_v2[] Parse(string[] lines, out int index)
24 | {
25 | index = 0;
26 |
27 | POLine_v2[] transactionLines = new POLine_v2[1000];
28 | POLine_v2 poLine = new POLine_v2();
29 |
30 | State state = State.ID;
31 | foreach (var line in lines)
32 | {
33 | if (string.IsNullOrEmpty(line))
34 | {
35 | if (state >= State.Note)
36 | {
37 | transactionLines[index] = poLine;
38 | state = State.ID;
39 | index++;
40 | }
41 |
42 | continue;
43 | }
44 | switch (state)
45 | {
46 | case State.ID:
47 | {
48 | poLine.ID = int.Parse(line);
49 |
50 | state++;
51 | break;
52 | }
53 | case State.DateTime:
54 | {
55 | var dt = line.Split('T');
56 | poLine.PODateTime.Date = dt[0];
57 | poLine.PODateTime.Time = dt[1];
58 |
59 | state++;
60 | break;
61 | }
62 | case State.Amount:
63 | {
64 | poLine.Amount = double.Parse(line);
65 |
66 | state++;
67 | break;
68 | }
69 | case State.Note:
70 | {
71 | poLine.Note += line;
72 |
73 | state++;
74 | break;
75 | }
76 | }
77 | }
78 |
79 | return transactionLines;
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/POParser/DoDPOParser_v3.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Reflection;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 |
8 | namespace DoDSamples.Samples
9 | {
10 |
11 | //
12 | // You might thing that this is better setting the pack but if you think about it, this data set breaks
13 | // aligment, and thus all potential gains will be nullified by missaligment.
14 | //
15 | //[StructLayout(LayoutKind.Sequential, Pack = 4)]
16 | public struct POLine_v3
17 | {
18 | public double Amount;
19 | public POData POData;
20 | }
21 |
22 | public struct POData
23 | {
24 | public int ID;
25 | public string Date;
26 | public string Time;
27 | public string Note;
28 | }
29 |
30 | public class DoDPOParser_v3
31 | {
32 | private enum State
33 | {
34 | ID,
35 | DateTime,
36 | Amount,
37 | Note
38 | }
39 |
40 | public List Parse(string path) => Parse(File.ReadAllLines(path));
41 |
42 | public List Parse(string[] lines)
43 | {
44 | List transactionLines = new List(1000);
45 | POLine_v3 poLine = new POLine_v3();
46 |
47 | State state = State.ID;
48 | foreach (var line in lines)
49 | {
50 | if (string.IsNullOrEmpty(line))
51 | {
52 | if (state >= State.Note)
53 | {
54 | transactionLines.Add(poLine);
55 | state = State.ID;
56 | }
57 |
58 | continue;
59 | }
60 | switch (state)
61 | {
62 | case State.ID:
63 | {
64 | poLine.POData.ID = int.Parse(line);
65 |
66 | state++;
67 | break;
68 | }
69 | case State.DateTime:
70 | {
71 | var dt = line.Split('T');
72 | poLine.POData.Date = dt[0];
73 | poLine.POData.Time = dt[1];
74 |
75 | state++;
76 | break;
77 | }
78 | case State.Amount:
79 | {
80 | poLine.Amount = double.Parse(line);
81 |
82 | state++;
83 | break;
84 | }
85 | case State.Note:
86 | {
87 | poLine.POData.Note += line;
88 |
89 | state++;
90 | break;
91 | }
92 | }
93 | }
94 |
95 | return transactionLines;
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/POParser/DoDPOParser_v3a.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Reflection;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 |
8 | namespace DoDSamples.Samples
9 | {
10 | public class DoDPOParser_v3a
11 | {
12 | private enum State
13 | {
14 | ID,
15 | DateTime,
16 | Amount,
17 | Note
18 | }
19 |
20 | public POLine_v3[] Parse(string path, out int index) => Parse(File.ReadAllLines(path), out index);
21 |
22 | public POLine_v3[] Parse(string[] lines, out int index)
23 | {
24 | index = 0;
25 |
26 | var transactionLines = new POLine_v3[1000];
27 | POLine_v3 poLine = new POLine_v3();
28 |
29 | State state = State.ID;
30 | foreach (var line in lines)
31 | {
32 | if (string.IsNullOrEmpty(line))
33 | {
34 | if (state >= State.Note)
35 | {
36 | transactionLines[index] = poLine;
37 | state = State.ID;
38 | index++;
39 | }
40 |
41 | continue;
42 | }
43 | switch (state)
44 | {
45 | case State.ID:
46 | {
47 | poLine.POData.ID = int.Parse(line);
48 |
49 | state++;
50 | break;
51 | }
52 | case State.DateTime:
53 | {
54 | var dt = line.Split('T');
55 | poLine.POData.Date = dt[0];
56 | poLine.POData.Time = dt[1];
57 |
58 | state++;
59 | break;
60 | }
61 | case State.Amount:
62 | {
63 | poLine.Amount = double.Parse(line);
64 |
65 | state++;
66 | break;
67 | }
68 | case State.Note:
69 | {
70 | poLine.POData.Note += line;
71 |
72 | state++;
73 | break;
74 | }
75 | }
76 | }
77 |
78 | return transactionLines;
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/POParser/DoDPOParser_v4.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Runtime.Intrinsics;
5 | using System.Runtime.Intrinsics.X86;
6 | using System.Text;
7 |
8 | namespace DoDSamples.Samples
9 | {
10 | public struct DoDPOLines_v4
11 | {
12 | public int[] ID;
13 | public double[] Amount;
14 | public string[] Date;
15 | public string[] Time;
16 | public string[] Note;
17 |
18 | public DoDPOLines_v4(int size)
19 | {
20 | ID = new int[size];
21 | Date = new string[size];
22 | Time = new string[size];
23 | Amount = new double[size];
24 | Note = new string[size];
25 | }
26 | }
27 |
28 | public class DoDPOParser_v4
29 | {
30 | private enum State
31 | {
32 | ID,
33 | DateTime,
34 | Amount,
35 | Note
36 | }
37 |
38 | public DoDPOLines_v4 Parse(string path, out int index) => Parse(File.ReadAllLines(path), out index);
39 |
40 | public DoDPOLines_v4 Parse(string[] lines, out int index)
41 | {
42 | DoDPOLines_v4 transactionLines = new DoDPOLines_v4(1000);
43 |
44 | index = 0;
45 | State state = State.ID;
46 | foreach (var line in lines)
47 | {
48 | if (string.IsNullOrEmpty(line))
49 | {
50 | if (state >= State.Note)
51 | {
52 | state = State.ID;
53 | index++;
54 | }
55 |
56 | continue;
57 | }
58 | switch (state)
59 | {
60 | case State.ID:
61 | {
62 | transactionLines.ID[index] = int.Parse(line);
63 |
64 | state++;
65 | break;
66 | }
67 | case State.DateTime:
68 | {
69 | var dt = line.Split('T');
70 | transactionLines.Date[index] = dt[0];
71 | transactionLines.Time[index] = dt[1];
72 |
73 | state++;
74 | break;
75 | }
76 | case State.Amount:
77 | {
78 | transactionLines.Amount[index] = double.Parse(line);
79 |
80 | state++;
81 | break;
82 | }
83 | case State.Note:
84 | {
85 | transactionLines.Note[index] += line;
86 |
87 | state++;
88 | break;
89 | }
90 | }
91 | }
92 |
93 | return transactionLines;
94 | }
95 |
96 |
97 | public unsafe double SumAmount(DoDPOLines_v4 source, int len)
98 | {
99 | double result;
100 |
101 | fixed (double* pSource = source.Amount)
102 | {
103 | Vector128 vresult = Vector128.Zero;
104 |
105 | int i = 0;
106 | int lastBlockIndex = len - (len % 2);
107 |
108 | while (i < lastBlockIndex)
109 | {
110 | vresult = Sse2.Add(vresult, Sse2.LoadVector128(pSource + i));
111 | i += 2;
112 | }
113 |
114 | vresult = Ssse3.HorizontalAdd(vresult, vresult);
115 | result = vresult.ToScalar();
116 |
117 | while (i < len)
118 | {
119 | result += pSource[i];
120 | i += 1;
121 | }
122 | }
123 |
124 | return result;
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/POParser/DoDPOParser_v5.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 |
6 | namespace DoDSamples.Samples
7 | {
8 | public struct DoDPOLines_v5
9 | {
10 | public int[] ID;
11 | public double[] Amount;
12 | public string[] Date;
13 | public string[] Time;
14 | public int[] NoteOffset;
15 | public StringBuilder AllNotes;
16 |
17 | public DoDPOLines_v5(int size)
18 | {
19 | ID = new int[size];
20 | Date = new string[size];
21 | Time = new string[size];
22 | Amount = new double[size];
23 | NoteOffset = new int[size];
24 | AllNotes = new StringBuilder(size);
25 | }
26 | }
27 |
28 | public class DoDPOParser_v5
29 | {
30 | private enum State
31 | {
32 | ID,
33 | DateTime,
34 | Amount,
35 | Note
36 | }
37 |
38 | public DoDPOLines_v5 Parse(string path, out int index) => Parse(File.ReadAllLines(path), out index);
39 |
40 | public DoDPOLines_v5 Parse(string[] lines, out int index)
41 | {
42 | DoDPOLines_v5 transactionLines = new DoDPOLines_v5(1000);
43 |
44 | int offset = 0;
45 | index = 0;
46 | State state = State.ID;
47 | foreach (var line in lines)
48 | {
49 | if (string.IsNullOrEmpty(line))
50 | {
51 | if (state >= State.Note)
52 | {
53 | state = State.ID;
54 | index++;
55 | }
56 |
57 | continue;
58 | }
59 | switch (state)
60 | {
61 | case State.ID:
62 | {
63 | transactionLines.ID[index] = int.Parse(line);
64 |
65 | state++;
66 | break;
67 | }
68 | case State.DateTime:
69 | {
70 | var dt = line.Split('T');
71 | transactionLines.Date[index] = dt[0];
72 | transactionLines.Time[index] = dt[1];
73 |
74 | state++;
75 | break;
76 | }
77 | case State.Amount:
78 | {
79 | transactionLines.Amount[index] = double.Parse(line);
80 |
81 | state++;
82 | break;
83 | }
84 | case State.Note:
85 | {
86 | offset += line.Length;
87 |
88 | transactionLines.NoteOffset[index] = offset;
89 | transactionLines.AllNotes.Append(line);
90 |
91 | state++;
92 | break;
93 | }
94 | }
95 | }
96 |
97 | return transactionLines;
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/POParser/OOPParser_Fast.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 |
6 | namespace DoDSamples.Samples
7 | {
8 | public class POLine
9 | {
10 | public int ID { get; set; }
11 | public string Date { get; set; }
12 | public string Time { get; set; }
13 | public double Amount { get; set; }
14 | public string Note { get; set; }
15 | }
16 |
17 | public class POParser_Fast
18 | {
19 | private enum State
20 | {
21 | ID,
22 | DateTime,
23 | Amount,
24 | Note
25 | }
26 |
27 | public List Parse(string path)
28 | {
29 | var lines = File.ReadAllLines(path);
30 | return Parse(lines);
31 | }
32 |
33 | public List Parse(string[] lines)
34 | {
35 | List transactionLines = new List(1000);
36 | POLine poLine = new POLine();
37 |
38 | State state = State.ID;
39 | foreach (var line in lines)
40 | {
41 | if (string.IsNullOrEmpty(line))
42 | {
43 | if (state >= State.Note)
44 | {
45 | transactionLines.Add(poLine);
46 | poLine = new POLine();
47 | state = State.ID;
48 | }
49 |
50 | continue;
51 | }
52 | switch (state)
53 | {
54 | case State.ID:
55 | {
56 | poLine.ID = int.Parse(line);
57 |
58 | state++;
59 | break;
60 | }
61 | case State.DateTime:
62 | {
63 | var dt = line.Split('T');
64 | poLine.Date = dt[0];
65 | poLine.Time = dt[1];
66 |
67 | state++;
68 | break;
69 | }
70 | case State.Amount:
71 | {
72 | poLine.Amount = double.Parse(line);
73 |
74 | state++;
75 | break;
76 | }
77 | case State.Note:
78 | {
79 | poLine.Note += line;
80 |
81 | state++;
82 | break;
83 | }
84 | }
85 | }
86 |
87 | return transactionLines;
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/DoDSamples/Samples/POParser/OOPParser_Slow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 | using System.Text.RegularExpressions;
6 |
7 | namespace DoDSamples.Samples
8 | {
9 | public class POParser
10 | {
11 | private static Regex matchPOLine =
12 | new Regex(
13 | @"(?\d)\r\n(?[0-9]{4}-[0-9]{2}-[0-9]{2})T(?