Skip to content

Commit 58b89a5

Browse files
author
Paulo Janotti
committed
Good perf test for 20_000
1 parent e4caf1e commit 58b89a5

File tree

4 files changed

+82
-41
lines changed

4 files changed

+82
-41
lines changed

coverlet.sln

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.core.tests", "test
1515
EndProject
1616
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.console", "src\coverlet.console\coverlet.console.csproj", "{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}"
1717
EndProject
18-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.tracker", "src\coverlet.tracker\coverlet.tracker.csproj", "{F4273009-536D-4999-A126-B0A2E3AA3E70}"
19-
EndProject
2018
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "coverlet.testsubject", "test\coverlet.testsubject\coverlet.testsubject.csproj", "{AE117FAA-C21D-4F23-917E-0C8050614750}"
2119
EndProject
2220
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "coverlet.core.performancetest", "test\coverlet.core.performancetest\coverlet.core.performancetest.csproj", "{C68CF6DE-F86C-4BCF-BAB9-7A60C320E1F9}"
@@ -79,18 +77,6 @@ Global
7977
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Release|x64.Build.0 = Release|Any CPU
8078
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Release|x86.ActiveCfg = Release|Any CPU
8179
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Release|x86.Build.0 = Release|Any CPU
82-
{F4273009-536D-4999-A126-B0A2E3AA3E70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
83-
{F4273009-536D-4999-A126-B0A2E3AA3E70}.Debug|Any CPU.Build.0 = Debug|Any CPU
84-
{F4273009-536D-4999-A126-B0A2E3AA3E70}.Debug|x64.ActiveCfg = Debug|Any CPU
85-
{F4273009-536D-4999-A126-B0A2E3AA3E70}.Debug|x64.Build.0 = Debug|Any CPU
86-
{F4273009-536D-4999-A126-B0A2E3AA3E70}.Debug|x86.ActiveCfg = Debug|Any CPU
87-
{F4273009-536D-4999-A126-B0A2E3AA3E70}.Debug|x86.Build.0 = Debug|Any CPU
88-
{F4273009-536D-4999-A126-B0A2E3AA3E70}.Release|Any CPU.ActiveCfg = Release|Any CPU
89-
{F4273009-536D-4999-A126-B0A2E3AA3E70}.Release|Any CPU.Build.0 = Release|Any CPU
90-
{F4273009-536D-4999-A126-B0A2E3AA3E70}.Release|x64.ActiveCfg = Release|Any CPU
91-
{F4273009-536D-4999-A126-B0A2E3AA3E70}.Release|x64.Build.0 = Release|Any CPU
92-
{F4273009-536D-4999-A126-B0A2E3AA3E70}.Release|x86.ActiveCfg = Release|Any CPU
93-
{F4273009-536D-4999-A126-B0A2E3AA3E70}.Release|x86.Build.0 = Release|Any CPU
9480
{AE117FAA-C21D-4F23-917E-0C8050614750}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
9581
{AE117FAA-C21D-4F23-917E-0C8050614750}.Debug|Any CPU.Build.0 = Debug|Any CPU
9682
{AE117FAA-C21D-4F23-917E-0C8050614750}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -124,7 +110,6 @@ Global
124110
{FA73E423-9790-4F35-B018-3C4E3CA338BA} = {E877EBA4-E78B-4F7D-A2D3-1E070FED04CD}
125111
{E7637CC6-43F7-461A-A0BF-3C14562419BD} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
126112
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E} = {E877EBA4-E78B-4F7D-A2D3-1E070FED04CD}
127-
{F4273009-536D-4999-A126-B0A2E3AA3E70} = {E877EBA4-E78B-4F7D-A2D3-1E070FED04CD}
128113
{AE117FAA-C21D-4F23-917E-0C8050614750} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
129114
{C68CF6DE-F86C-4BCF-BAB9-7A60C320E1F9} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
130115
EndGlobalSection

src/coverlet.core/Instrumentation/Instrumenter.cs

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ internal class Instrumenter
2626
private FieldDefinition _customModuleTrackerHitsArray;
2727
private FieldDefinition _customModuleTrackerHitsFilePath;
2828
private ILProcessor _customModuleTrackerClassConstructorIl;
29+
private TypeDefinition _customTrackerTypeDef;
2930
private MethodReference _cachedInterlockedIncMethod;
3031

3132
public Instrumenter(string module, string identifier, string[] excludeFilters, string[] includeFilters, string[] excludedFiles)
@@ -101,14 +102,16 @@ private void AddCustomModuleTrackerToModule(ModuleDefinition module)
101102
TypeDefinition moduleTrackerTemplate = xad.MainModule.GetType(
102103
"Coverlet.Core.Instrumentation", nameof(ModuleTrackerTemplate));
103104

104-
TypeDefinition customTrackerTypeDef = new TypeDefinition(
105+
_customTrackerTypeDef = new TypeDefinition(
105106
"Coverlet.Core.Instrumentation.Tracker", Path.GetFileNameWithoutExtension(module.Name) + "_" + _identifier, moduleTrackerTemplate.Attributes);
106107

107-
customTrackerTypeDef.BaseType = module.TypeSystem.Object;
108+
_customTrackerTypeDef.BaseType = module.TypeSystem.Object;
108109
foreach (FieldDefinition fieldDef in moduleTrackerTemplate.Fields)
109110
{
110111
var fieldClone = new FieldDefinition(fieldDef.Name, fieldDef.Attributes, fieldDef.FieldType);
111-
customTrackerTypeDef.Fields.Add(fieldClone);
112+
fieldClone.FieldType = module.ImportReference(fieldClone.FieldType);
113+
114+
_customTrackerTypeDef.Fields.Add(fieldClone);
112115

113116
if (fieldClone.Name == "HitsArray")
114117
_customModuleTrackerHitsArray = fieldClone;
@@ -120,6 +123,14 @@ private void AddCustomModuleTrackerToModule(ModuleDefinition module)
120123
{
121124
MethodDefinition methodOnCustomType = new MethodDefinition(methodDef.Name, methodDef.Attributes, methodDef.ReturnType);
122125

126+
if (methodDef.Name == "RecordHit")
127+
{
128+
foreach (var parameter in methodDef.Parameters)
129+
{
130+
methodOnCustomType.Parameters.Add(new ParameterDefinition(module.ImportReference(parameter.ParameterType)));
131+
}
132+
}
133+
123134
foreach (var variable in methodDef.Body.Variables)
124135
{
125136
methodOnCustomType.Body.Variables.Add(new VariableDefinition(module.ImportReference(variable.VariableType)));
@@ -144,12 +155,12 @@ private void AddCustomModuleTrackerToModule(ModuleDefinition module)
144155
{
145156
// Move to the custom type
146157
instr.Operand = new MethodReference(
147-
methodReference.Name, methodReference.ReturnType, customTrackerTypeDef);
158+
methodReference.Name, methodReference.ReturnType, _customTrackerTypeDef);
148159
}
149160
}
150161
else if (instr.Operand is FieldReference fieldReference)
151162
{
152-
instr.Operand = customTrackerTypeDef.Fields.Single(fd => fd.Name == fieldReference.Name);
163+
instr.Operand = _customTrackerTypeDef.Fields.Single(fd => fd.Name == fieldReference.Name);
153164
}
154165
else if (instr.Operand is TypeReference typeReference)
155166
{
@@ -162,10 +173,10 @@ private void AddCustomModuleTrackerToModule(ModuleDefinition module)
162173
foreach (var handler in methodDef.Body.ExceptionHandlers)
163174
methodOnCustomType.Body.ExceptionHandlers.Add(handler);
164175

165-
customTrackerTypeDef.Methods.Add(methodOnCustomType);
176+
_customTrackerTypeDef.Methods.Add(methodOnCustomType);
166177
}
167178

168-
module.Types.Add(customTrackerTypeDef);
179+
module.Types.Add(_customTrackerTypeDef);
169180
}
170181

171182
Debug.Assert(_customModuleTrackerHitsArray != null);
@@ -234,7 +245,7 @@ private void InstrumentIL(MethodDefinition method)
234245
foreach (ExceptionHandler handler in processor.Body.ExceptionHandlers)
235246
ReplaceExceptionHandlerBoundary(handler, instruction, target);
236247

237-
index += 5;
248+
index += 2;
238249
}
239250

240251
foreach (var _branchTarget in targetedBranchPoints)
@@ -255,7 +266,7 @@ private void InstrumentIL(MethodDefinition method)
255266
foreach (ExceptionHandler handler in processor.Body.ExceptionHandlers)
256267
ReplaceExceptionHandlerBoundary(handler, instruction, target);
257268

258-
index += 5;
269+
index += 2;
259270
}
260271

261272
index++;
@@ -282,7 +293,7 @@ private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor
282293
var entry = (false, document.Index, sequencePoint.StartLine, sequencePoint.EndLine);
283294
_result.HitCandidates.Add(entry);
284295

285-
return AddInstrumentationInstructions(method, processor, instruction, _result.HitCandidates.Count);
296+
return AddInstrumentationInstructions(method, processor, instruction, _result.HitCandidates.Count - 1);
286297
}
287298

288299
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, BranchPoint branchPoint)
@@ -312,31 +323,45 @@ private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor
312323
var entry = (true, document.Index, branchPoint.StartLine, (int)branchPoint.Ordinal);
313324
_result.HitCandidates.Add(entry);
314325

315-
return AddInstrumentationInstructions(method, processor, instruction, _result.HitCandidates.Count);
326+
return AddInstrumentationInstructions(method, processor, instruction, _result.HitCandidates.Count - 1);
316327
}
317328

318329
private Instruction AddInstrumentationInstructions(MethodDefinition method, ILProcessor processor, Instruction instruction, int hitEntryIndex)
319330
{
320331
if (_cachedInterlockedIncMethod == null)
321332
{
322333
_cachedInterlockedIncMethod = new MethodReference(
323-
"Increment", method.Module.TypeSystem.Int32, method.Module.ImportReference(typeof(System.Threading.Interlocked)));
324-
_cachedInterlockedIncMethod.Parameters.Add(new ParameterDefinition(new ByReferenceType(method.Module.TypeSystem.Int32)));
334+
"RecordHit", method.Module.TypeSystem.Void, _customTrackerTypeDef);
335+
_cachedInterlockedIncMethod.Parameters.Add(new ParameterDefinition(method.Module.TypeSystem.Int32));
325336
}
326337

327-
var sfldInstr = Instruction.Create(OpCodes.Ldsfld, _customModuleTrackerHitsArray);
328338
var indxInstr = Instruction.Create(OpCodes.Ldc_I4, hitEntryIndex);
329-
var arefInstr = Instruction.Create(OpCodes.Ldelema, method.Module.TypeSystem.Int32);
330339
var callInstr = Instruction.Create(OpCodes.Call, _cachedInterlockedIncMethod);
331-
var popInstr = Instruction.Create(OpCodes.Pop);
332-
333-
processor.InsertBefore(instruction, popInstr);
334-
processor.InsertBefore(popInstr, callInstr);
335-
processor.InsertBefore(callInstr, arefInstr);
336-
processor.InsertBefore(arefInstr, indxInstr);
337-
processor.InsertBefore(indxInstr, sfldInstr);
338340

339-
return sfldInstr;
341+
processor.InsertBefore(instruction, callInstr);
342+
processor.InsertBefore(callInstr, indxInstr);
343+
344+
return indxInstr;
345+
//if (_cachedInterlockedIncMethod == null)
346+
//{
347+
// _cachedInterlockedIncMethod = new MethodReference(
348+
// "Increment", method.Module.TypeSystem.Int32, method.Module.ImportReference(typeof(System.Threading.Interlocked)));
349+
// _cachedInterlockedIncMethod.Parameters.Add(new ParameterDefinition(new ByReferenceType(method.Module.TypeSystem.Int32)));
350+
//}
351+
352+
//var sfldInstr = Instruction.Create(OpCodes.Ldsfld, _customModuleTrackerHitsArray);
353+
//var indxInstr = Instruction.Create(OpCodes.Ldc_I4, hitEntryIndex);
354+
//var arefInstr = Instruction.Create(OpCodes.Ldelema, method.Module.TypeSystem.Int32);
355+
//var callInstr = Instruction.Create(OpCodes.Call, _cachedInterlockedIncMethod);
356+
//var popInstr = Instruction.Create(OpCodes.Pop);
357+
358+
//processor.InsertBefore(instruction, popInstr);
359+
//processor.InsertBefore(popInstr, callInstr);
360+
//processor.InsertBefore(callInstr, arefInstr);
361+
//processor.InsertBefore(arefInstr, indxInstr);
362+
//processor.InsertBefore(indxInstr, sfldInstr);
363+
364+
//return sfldInstr;
340365
}
341366

342367
private static void ReplaceInstructionTarget(Instruction instruction, Instruction oldTarget, Instruction newTarget)

src/coverlet.core/Instrumentation/ModuleTrackerTemplate.cs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.IO;
34
using System.Threading;
45

@@ -15,20 +16,50 @@ namespace Coverlet.Core.Instrumentation
1516
public static class ModuleTrackerTemplate
1617
{
1718
public static string HitsFilePath;
19+
public static int[] HitsArray;
1820

19-
public readonly static int[] HitsArray;
21+
[ThreadStatic]
22+
private static int[] threadHits;
23+
24+
private static List<int[]> threads;
2025

2126
static ModuleTrackerTemplate()
2227
{
28+
threads = new List<int[]>(2 * Environment.ProcessorCount);
29+
2330
AppDomain.CurrentDomain.ProcessExit += new EventHandler(UnloadModule);
2431
AppDomain.CurrentDomain.DomainUnload += new EventHandler(UnloadModule);
2532
// At the end of the instrumentation of a module, the instrumenter needs to add code here
2633
// to initialize the static fields according to the values derived from the instrumentation of
2734
// the module.
2835
}
2936

37+
public static void RecordHit(int hitLocationIndex)
38+
{
39+
if (threadHits == null)
40+
{
41+
lock (threads)
42+
{
43+
threadHits = new int[HitsArray.Length];
44+
threads.Add(threadHits);
45+
}
46+
}
47+
48+
++threadHits[hitLocationIndex];
49+
}
50+
3051
public static void UnloadModule(object sender, EventArgs e)
3152
{
53+
// Update the global hits array from data from all the threads
54+
lock (threads)
55+
{
56+
foreach (var threadHits in threads)
57+
{
58+
for (int i = 0; i < HitsArray.Length; ++i)
59+
HitsArray[i] += threadHits[i];
60+
}
61+
}
62+
3263
// TODO: same module can be unloaded multiple times in the same process. Need to check and handle this case.
3364
// TODO: perhaps some kind of global mutex based on the name of the modules hits file, and after the first
3465
// TODO: they update the hit count from the file already created. Something like this, (minus the read stuff):

test/coverlet.core.performancetest/PerformanceTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ namespace coverlet.core.performancetest
1515
public class PerformanceTest
1616
{
1717
[Theory(/*Skip = "Only enabled when explicitly testing performance."*/)]
18-
[InlineData(150)]
19-
// [InlineData(20_000)]
18+
// [InlineData(150)]
19+
[InlineData(20_000)]
2020
public void TestPerformance(int iterations)
2121
{
2222
var big = new BigClass();

0 commit comments

Comments
 (0)