1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.IO;
6 using System.Collections.Generic;
7 using System.Linq;
8 using Microsoft.Xunit.Performance;
9 using System.Xml;
10 using SerializationTypes;
11 
12 namespace System.Runtime.Serialization
13 {
14     #region Performance tests configuration types
15 
16     public enum TestType
17     {
18         SimpleType,
19         ISerializable,
20         Dictionary,
21         ListOfInt,
22         String,
23         ByteArray,
24         XmlElement,
25         DateTimeArray,
26         ArrayOfSimpleType,
27         ListOfSimpleType,
28         DictionaryOfSimpleType,
29         SimpleStructWithProperties,
30         SimpleTypeWithFields
31     }
32 
33     public interface IPerfTestSerializer
34     {
Init(object obj)35         void Init(object obj);
Serialize(object obj, Stream s)36         void Serialize(object obj, Stream s);
Deserialize(Stream s)37         void Deserialize(Stream s);
38     }
39 
40     public interface ISerializerFactory
41     {
GetSerializer()42         IPerfTestSerializer GetSerializer();
43     }
44 
45     public class PerfTestConfig
46     {
47         public readonly int NumberOfRuns;
48         public readonly TestType PerfTestType;
49         public readonly int TestSize;
50 
PerfTestConfig()51         public PerfTestConfig() { }
52 
PerfTestConfig(int numOfRuns, TestType testType, int testSize)53         public PerfTestConfig(int numOfRuns, TestType testType, int testSize)
54         {
55             NumberOfRuns = numOfRuns;
56             PerfTestType = testType;
57             TestSize = testSize;
58         }
59 
ToObjectArray()60         public object[] ToObjectArray()
61         {
62             return new object[] { NumberOfRuns, PerfTestType, TestSize };
63         }
64     }
65 
66     #endregion
67 
68     public class PerformanceTestCommon
69     {
70         #region Performance test configuration
71 
PerformanceTestConfigurations()72         public static IEnumerable<PerfTestConfig> PerformanceTestConfigurations()
73         {
74             yield return new PerfTestConfig(100, TestType.ByteArray, 1024);
75             yield return new PerfTestConfig(5, TestType.ByteArray, 1024 * 1024);
76             yield return new PerfTestConfig(10000, TestType.String, 128);
77             yield return new PerfTestConfig(10000, TestType.String, 1024);
78             yield return new PerfTestConfig(1000, TestType.ListOfInt, 128);
79             yield return new PerfTestConfig(100, TestType.ListOfInt, 1024);
80             yield return new PerfTestConfig(1, TestType.ListOfInt, 1024 * 1024);
81             yield return new PerfTestConfig(1000, TestType.Dictionary, 128);
82             yield return new PerfTestConfig(100, TestType.Dictionary, 1024);
83             yield return new PerfTestConfig(10, TestType.SimpleType, 1);
84             yield return new PerfTestConfig(1, TestType.SimpleType, 15);
85             yield return new PerfTestConfig(1, TestType.SimpleTypeWithFields, 15);
86             yield return new PerfTestConfig(10000, TestType.SimpleStructWithProperties, 1);
87             yield return new PerfTestConfig(10000, TestType.ISerializable, -1);
88             yield return new PerfTestConfig(10000, TestType.XmlElement, -1);
89             yield return new PerfTestConfig(100, TestType.DateTimeArray, 1024);
90             yield return new PerfTestConfig(1000, TestType.ArrayOfSimpleType, 128);
91             yield return new PerfTestConfig(100, TestType.ArrayOfSimpleType, 1024);
92             yield return new PerfTestConfig(1000, TestType.ListOfSimpleType, 128);
93             yield return new PerfTestConfig(100, TestType.ListOfSimpleType, 1024);
94             yield return new PerfTestConfig(1000, TestType.DictionaryOfSimpleType, 128);
95             yield return new PerfTestConfig(100, TestType.DictionaryOfSimpleType, 1024);
96         }
97 
PerformanceMemberData()98         public static IEnumerable<object[]> PerformanceMemberData()
99         {
100             foreach (PerfTestConfig config in PerformanceTestConfigurations())
101             {
102                 yield return config.ToObjectArray();
103             }
104         }
105 
106         #endregion
107 
108         #region Methods to create object for serialization tests
109 
CreateSimpleTypeWihtMoreProperties(int height, int parentId, int currentId, int collectionSize, int childListSize)110         public static SimpleTypeWihtMoreProperties CreateSimpleTypeWihtMoreProperties(int height, int parentId, int currentId, int collectionSize, int childListSize)
111         {
112             int index = parentId * childListSize + (currentId + 1);
113             var obj = new SimpleTypeWihtMoreProperties()
114             {
115                 IntProperty = index,
116                 StringProperty = index + " string value",
117                 EnumProperty = (MyEnum)(index % (Enum.GetNames(typeof(MyEnum)).Length)),
118                 CollectionProperty = new List<string>(collectionSize),
119                 SimpleTypeList = new List<SimpleTypeWihtMoreProperties>(childListSize)
120             };
121             for (int i = 0; i < collectionSize; ++i)
122             {
123                 obj.CollectionProperty.Add(index + "." + i);
124             }
125             if (height > 1)
126             {
127                 for (int i = 0; i < childListSize; ++i)
128                 {
129                     obj.SimpleTypeList.Add(CreateSimpleTypeWihtMoreProperties(height - 1, index, i, collectionSize, childListSize));
130                 }
131             }
132             return obj;
133         }
134 
CreateSimpleTypeWithFields(int height, int parentId, int currentId, int collectionSize, int childListSize)135         public static SimpleTypeWithMoreFields CreateSimpleTypeWithFields(int height, int parentId, int currentId, int collectionSize, int childListSize)
136         {
137             int index = parentId * childListSize + (currentId + 1);
138             var obj = new SimpleTypeWithMoreFields()
139             {
140                 IntField = index,
141                 StringField = index + " string value",
142                 EnumField = (MyEnum)(index % (Enum.GetNames(typeof(MyEnum)).Length)),
143                 CollectionField = new List<string>(collectionSize),
144                 SimpleTypeList = new List<SimpleTypeWithMoreFields>(childListSize)
145             };
146             for (int i = 0; i < collectionSize; ++i)
147             {
148                 obj.CollectionField.Add(index + "." + i);
149             }
150             if (height > 1)
151             {
152                 for (int i = 0; i < childListSize; ++i)
153                 {
154                     obj.SimpleTypeList.Add(CreateSimpleTypeWithFields(height - 1, index, i, collectionSize, childListSize));
155                 }
156             }
157             return obj;
158         }
159 
CreateByteArray(int size)160         public static byte[] CreateByteArray(int size)
161         {
162             byte[] obj = new byte[size];
163             for (int i = 0; i < obj.Length; ++i)
164             {
165                 unchecked
166                 {
167                     obj[i] = (byte)i;
168                 }
169             }
170             return obj;
171         }
172 
CreateDictionaryOfIntString(int count)173         public static Dictionary<int, string> CreateDictionaryOfIntString(int count)
174         {
175             Dictionary<int, string> dictOfIntString = new Dictionary<int, string>(count);
176             for (int i = 0; i < count; ++i)
177             {
178                 dictOfIntString[i] = i.ToString();
179             }
180 
181             return dictOfIntString;
182         }
183 
CreateDictionaryOfIntSimpleType(int count)184         public static Dictionary<int, SimpleType> CreateDictionaryOfIntSimpleType(int count)
185         {
186             var dictOfIntSimpleType = new Dictionary<int, SimpleType>(count);
187             for (int i = 0; i < count; ++i)
188             {
189                 dictOfIntSimpleType[i] = new SimpleType() { P1 = i.ToString(), P2 = i };
190             }
191 
192             return dictOfIntSimpleType;
193         }
194 
CreateListOfSimpleType(int count)195         public static List<SimpleType> CreateListOfSimpleType(int count)
196         {
197             var listOfSimpleType = new List<SimpleType>(count);
198             for(int i = 0; i < count; i++)
199             {
200                 listOfSimpleType.Add(new SimpleType() { P1 = i.ToString(), P2 = i });
201             }
202 
203             return listOfSimpleType;
204         }
205 
CreateArrayOfSimpleType(int count)206         public static SimpleType[] CreateArrayOfSimpleType(int count)
207         {
208             var arrayOfSimpleType = new SimpleType[count];
209             for(int i = 0; i < count; i++)
210             {
211                 arrayOfSimpleType[i] = new SimpleType() { P1 = i.ToString(), P2 = i };
212             }
213 
214             return arrayOfSimpleType;
215         }
216 
CreateListOfInt(int count)217         public static List<int> CreateListOfInt(int count)
218         {
219             return Enumerable.Range(0, count).ToList();
220         }
221 
CreateDateTimeArray(int count)222         public static DateTime[] CreateDateTimeArray(int count)
223         {
224             DateTime[] arr = new DateTime[count];
225             int kind = (int)DateTimeKind.Unspecified;
226             int maxDateTimeKind = (int) DateTimeKind.Local;
227             DateTime val = DateTime.Now.AddHours(count/2);
228             for (int i = 0; i < count; i++)
229             {
230                 arr[i] = DateTime.SpecifyKind(val, (DateTimeKind)kind);
231                 val = val.AddHours(1);
232                 kind = (kind + 1)%maxDateTimeKind;
233             }
234 
235             return arr;
236         }
237 
GetSerializationObject(TestType testType, int testSize)238         public static object GetSerializationObject(TestType testType, int testSize)
239         {
240             Object obj = null;
241             switch (testType)
242             {
243                 case TestType.ByteArray:
244                     obj = CreateByteArray(testSize);
245                     break;
246                 case TestType.Dictionary:
247                     obj = CreateDictionaryOfIntString(testSize);
248                     break;
249                 case TestType.ISerializable:
250                     obj = new ClassImplementingIXmlSerialiable() { StringValue = "Hello world" };
251                     break;
252                 case TestType.ListOfInt:
253                     obj = CreateListOfInt(testSize);
254                     break;
255                 case TestType.SimpleType:
256                     obj = CreateSimpleTypeWihtMoreProperties(testSize, 0, -1, 7, 2);
257                     break;
258                 case TestType.SimpleTypeWithFields:
259                      obj = CreateSimpleTypeWithFields(testSize, 0, -1, 7, 2);
260                     break;
261                 case TestType.String:
262                     obj = new string('k', testSize);
263                     break;
264                 case TestType.XmlElement:
265                     XmlDocument xmlDoc = new XmlDocument();
266                     xmlDoc.LoadXml(@"<html></html>");
267                     XmlElement xmlElement = xmlDoc.CreateElement("Element");
268                     xmlElement.InnerText = "Element innertext";
269                     obj = xmlElement;
270                     break;
271                 case TestType.DateTimeArray:
272                     obj = CreateDateTimeArray(testSize);
273                     break;
274                 case TestType.ArrayOfSimpleType:
275                     obj = CreateArrayOfSimpleType(testSize);
276                     break;
277                 case TestType.ListOfSimpleType:
278                     obj = CreateListOfSimpleType(testSize);
279                     break;
280                 case TestType.DictionaryOfSimpleType:
281                     obj = CreateDictionaryOfIntSimpleType(testSize);
282                     break;
283                 case TestType.SimpleStructWithProperties:
284                     obj = new SimpleStructWithProperties() { Num = 1, Text = "Foo" };
285                     break;
286                 default:
287                     throw new ArgumentException();
288             }
289             return obj;
290         }
291 
292         #endregion
293 
294         #region Methods to run serialization performance tests
295 
RunSerializationPerformanceTest(int numberOfRuns, TestType testType, int testSize, ISerializerFactory serializerFactory)296         public static void RunSerializationPerformanceTest(int numberOfRuns, TestType testType, int testSize, ISerializerFactory serializerFactory)
297         {
298             var obj = GetSerializationObject(testType, testSize);
299 
300             var serializer = serializerFactory.GetSerializer();
301             serializer.Init(obj);
302 
303             using (var stream = new MemoryStream())
304             {
305                 foreach (var iteration in Benchmark.Iterations)
306                 {
307                     using (iteration.StartMeasurement())
308                     {
309                         for (int i = 0; i < numberOfRuns; i++)
310                         {
311                             serializer.Serialize(obj, stream);
312                             stream.Position = 0;
313                         }
314                     }
315                 }
316             }
317         }
318 
RunDeserializationPerformanceTest(int numberOfRuns, TestType testType, int testSize, ISerializerFactory serializerFactory)319         public static void RunDeserializationPerformanceTest(int numberOfRuns, TestType testType, int testSize, ISerializerFactory serializerFactory)
320         {
321             var obj = GetSerializationObject(testType, testSize);
322 
323             var serializer = serializerFactory.GetSerializer();
324             serializer.Init(obj);
325 
326             using (var stream = new MemoryStream())
327             {
328                 serializer.Serialize(obj, stream);
329                 stream.Position = 0;
330                 foreach (var iteration in Benchmark.Iterations)
331                 {
332                     using (iteration.StartMeasurement())
333                     {
334                         for (int i = 0; i < numberOfRuns; i++)
335                         {
336                             serializer.Deserialize(stream);
337                             stream.Position = 0;
338                         }
339                     }
340                 }
341             }
342         }
343 
344         #endregion
345     }
346 }
347