Skip to content

Commit c558624

Browse files
author
Jonathan Gaillard
committed
Use a seperate hits file per process/thread in order to use a seperate writer per process/thread to reduce contention when multiple multi threaded programs are generating hits concurrently.
1 parent 2f2eedb commit c558624

File tree

3 files changed

+38
-19
lines changed

3 files changed

+38
-19
lines changed

Gaillard.SharpCover.Tests/ProgramTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ public void Covered()
5656

5757
File.WriteAllText("testConfig.json", config);
5858

59+
//write some extraneous hit files to make sure they dont affect run
60+
File.WriteAllText(Program.HITS_FILENAME_PREFIX, "doesnt matter");
61+
5962
Assert.AreEqual(0, Program.Main(new []{ "instrument", "testConfig.json" }));
6063

6164
Process.Start(testTargetExePath).WaitForExit();

Gaillard.SharpCover/Counter.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,30 @@
22
using System.IO;
33
using System.Collections.Generic;
44
using System.Reflection;
5+
using System.Threading;
6+
using System.Diagnostics;
57

6-
[assembly: AssemblyVersion("1.0.1.*")]
8+
[assembly: AssemblyVersion("1.0.2.*")]
79

810
namespace Gaillard.SharpCover
911
{
1012
public static class Counter
1113
{
14+
[ThreadStatic]
15+
private static HashSet<int> indexes;
16+
17+
[ThreadStatic]
1218
private static BinaryWriter writer;
13-
private static readonly ISet<int> indexes = new HashSet<int>();
1419

15-
public static void Count(string path, int index)
20+
[ThreadStatic]
21+
private static string path;
22+
23+
public static void Count(string pathPrefix, int index)
1624
{
17-
if (writer == null) {
18-
writer = new BinaryWriter(File.Open(path, FileMode.Append));
25+
if (path == null) {
26+
path = pathPrefix + "|" + Process.GetCurrentProcess().Id + "|" + Thread.CurrentThread.ManagedThreadId;
27+
indexes = new HashSet<int>();
28+
writer = new BinaryWriter(File.Open(path, FileMode.CreateNew));
1929
}
2030

2131
if (indexes.Add(index))

Gaillard.SharpCover/Program.cs

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
using System.Text.RegularExpressions;
1010
using Newtonsoft.Json.Linq;
1111

12-
[assembly: AssemblyVersion("1.0.1.*")]
12+
[assembly: AssemblyVersion("1.0.2.*")]
1313

1414
namespace Gaillard.SharpCover
1515
{
1616
public static class Program
1717
{
18-
public const string RESULTS_FILENAME = "coverageResults.txt", MISS_PREFIX = "MISS ! ";
19-
private const string KNOWNS_FILENAME = "coverageKnowns", HITS_FILENAME = "coverageHits";
18+
public const string RESULTS_FILENAME = "coverageResults.txt", MISS_PREFIX = "MISS ! ", HITS_FILENAME_PREFIX = "coverageHits";
19+
private const string KNOWNS_FILENAME = "coverageKnowns";
2020
private static readonly MethodInfo countMethodInfo = typeof(Counter).GetMethod("Count");
2121

2222
//immutable
@@ -27,7 +27,7 @@ private sealed class InstrumentConfig
2727
TypeExclude,
2828
MethodInclude,
2929
MethodExclude,
30-
HitsPath = Path.Combine(Directory.GetCurrentDirectory(), HITS_FILENAME);
30+
HitsPathPrefix = Path.Combine(Directory.GetCurrentDirectory(), HITS_FILENAME_PREFIX);
3131
private readonly IDictionary<string, IEnumerable<int>> methodOffsetExcludes = new Dictionary<string, IEnumerable<int>>();
3232
private readonly IDictionary<string, IEnumerable<string>> methodLineExcludes = new Dictionary<string, IEnumerable<string>>();
3333

@@ -100,7 +100,7 @@ private static void Instrument(Instruction instruction,
100100

101101
writer.WriteLine(line);
102102

103-
var pathParamLoadInstruction = worker.Create(OpCodes.Ldstr, config.HitsPath);
103+
var pathParamLoadInstruction = worker.Create(OpCodes.Ldstr, config.HitsPathPrefix);
104104
var lineParamLoadInstruction = worker.Create(OpCodes.Ldc_I4, instrumentIndex);
105105
var registerInstruction = worker.Create(OpCodes.Call, countReference);
106106

@@ -211,11 +211,15 @@ private static void Instrument(string assemblyPath, InstrumentConfig config, Tex
211211

212212
private static int Check()
213213
{
214+
var currentDirectory = Directory.GetCurrentDirectory();
215+
214216
var hits = new HashSet<int>();
215-
using (var hitsStream = File.OpenRead(HITS_FILENAME))
216-
using (var hitsReader = new BinaryReader(hitsStream)) {
217-
while(hitsStream.Position < hitsStream.Length)
218-
hits.Add(hitsReader.ReadInt32());
217+
foreach (var hitsPath in Directory.GetFiles(currentDirectory, HITS_FILENAME_PREFIX + "*")) {
218+
using (var hitsStream = File.OpenRead(hitsPath))
219+
using (var hitsReader = new BinaryReader(hitsStream)) {
220+
while (hitsStream.Position < hitsStream.Length)
221+
hits.Add (hitsReader.ReadInt32());
222+
}
219223
}
220224

221225
var missCount = 0;
@@ -234,7 +238,9 @@ private static int Check()
234238
}
235239
}
236240

237-
File.Delete(HITS_FILENAME);
241+
//cleanup to leave only results file
242+
foreach (var hitsPath in Directory.GetFiles(currentDirectory, HITS_FILENAME_PREFIX + "*"))
243+
File.Delete(hitsPath);
238244
File.Delete(KNOWNS_FILENAME);
239245

240246
var missRatio = (double)missCount / (double)knownIndex;
@@ -251,14 +257,14 @@ public static int Main(string[] args)
251257
if (args[0] == "instrument") {
252258
var config = new InstrumentConfig(args[1]);
253259

254-
//so it exists regardless and is deleted
255-
File.WriteAllText(KNOWNS_FILENAME, string.Empty);
256-
File.WriteAllText(config.HitsPath, string.Empty);
260+
//delete existing hit files generatig during program exercising
261+
foreach (var hitsPath in Directory.GetFiles(Directory.GetCurrentDirectory(), HITS_FILENAME_PREFIX + "*"))
262+
File.Delete(hitsPath);
257263

258264
//used to track the line index of the instrumented instruction in the knowns file
259265
var instrumentIndex = 0;
260266

261-
using (var writer = new StreamWriter(KNOWNS_FILENAME, true)) {
267+
using (var writer = new StreamWriter(KNOWNS_FILENAME)) {//overwrites
262268
foreach (var assemblyPath in config.AssemblyPaths)
263269
Instrument(assemblyPath, config, writer, ref instrumentIndex);
264270
}

0 commit comments

Comments
 (0)