-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathFindMedianCommitTime.java
More file actions
145 lines (132 loc) · 6.15 KB
/
FindMedianCommitTime.java
File metadata and controls
145 lines (132 loc) · 6.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package org.variantsync.diffdetective.experiments.esecfse22;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.tinylog.Logger;
import org.variantsync.diffdetective.analysis.AutomationResult;
import org.variantsync.diffdetective.analysis.CommitProcessTime;
import org.variantsync.diffdetective.analysis.StatisticsAnalysis;
import org.variantsync.diffdetective.util.FileUtils;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Program to find the median commit time after the {@link EditClassValidation} has been performed.
* This program will iterate through all commit times reported by the validation, load them,
* and find average time, median time, the fastest, and the slowest commit.
* @author Paul Bittner
*/
public class FindMedianCommitTime {
/**
* File to write the result to.
*/
public static final Path outputFile = Path.of("speedstatistics.txt");
/**
* Main method. Expects exactly one argument: The path to the root directory of the validation output.
* @param args An array of size 1, containing the path to validation output is expected.
* @throws IOException when {@link #getResultOfDirectory} throws.
*/
public static void main(final String[] args) throws IOException {
if (args.length < 1) {
throw new IllegalArgumentException("Expected path to input directory but got no arguments!");
}
final Path inputPath = Path.of(args[0]);
final AutomationResult automationResult = getResultOfDirectory(inputPath);
final String resultsStr = automationResult.exportTo(inputPath.resolve(outputFile));
Logger.info("Results:{}", resultsStr);
// Logger.info("info");
// Logger.warn("warn");
// Logger.error("error");
// Logger.debug("debug");
// Logger.trace("trace");
}
/**
* Summarizes the commit time results found in the given validation output directory.
* The directory should point to the root of the directory in which the results of an execution
* of the {@link EditClassValidation} can be found.
* @param directory Validation output directory.
* @return Summary of commit process times with various speed statistics.
* @throws IOException when iterating the files in the given directory fails for some reason.
*/
public static AutomationResult getResultOfDirectory(final Path directory) throws IOException {
if (!Files.isDirectory(directory)) {
throw new IllegalArgumentException("Expected path to directory but "+ directory +" is not a directory!");
}
// This stream needs {@code O(n log(n))} time (because of the sort) and {@code O(n)} space
// (because the list has to be captured). This can be improved to {@code O(n)} time and
// {@code O(1)} space by using the Median of medians algorithm and computing the minimum and
// maximum like {@code LongSummaryStatistics} does.
ImmutablePair<Long, List<CommitProcessTime>> result;
try (Stream<Path> paths = Files.walk(directory)) {
result = paths
.parallel()
.filter(p -> FileUtils.hasExtension(p, StatisticsAnalysis.COMMIT_TIME_FILE_EXTENSION))
.filter(Files::isRegularFile)
// .peek(path -> Logger.info("Processing file {}", path))
.flatMap(FindMedianCommitTime::parse)
.sorted(Comparator.comparingDouble(CommitProcessTime::milliseconds))
.collect(Collectors.teeing(
Collectors.summingLong(CommitProcessTime::milliseconds),
Collectors.toList(),
ImmutablePair::new)
);
} catch (UncheckedIOException e) {
throw e.getCause();
}
long totalTimeMS = result.getLeft();
List<CommitProcessTime> alltimes = result.getRight();
// if (alltimes.size() != numExpectedCommits) {
// Logger.error("Expected {} commits but got {}! {} commits are missing!",
// numExpectedCommits,
// alltimes.size(),
// numExpectedCommits - alltimes.size());
// }
if (alltimes.size() == 0) {
final String repoName = directory.getFileName().toString();
return new AutomationResult(
alltimes.size(),
totalTimeMS,
CommitProcessTime.Invalid(repoName),
CommitProcessTime.Invalid(repoName),
CommitProcessTime.Invalid(repoName)
);
} else {
return new AutomationResult(
alltimes.size(),
totalTimeMS,
alltimes.get(0),
alltimes.get(alltimes.size() - 1),
alltimes.get(alltimes.size() / 2)
);
}
}
/**
* Parses all CommitProcessTimes in the given file.
* @param file Path to a commit times file (ending with <code>.committimes.txt</code>).
* @return A stream of the CommitProcessTimes in the given file.
*/
private static Stream<CommitProcessTime> parse(final Path file) {
try {
// This stream has to be closed by the caller of {@code parse}, because the returned
// stream is not consumed inside of this method.
return Files.lines(file)
.filter(
line -> {
if (line.isBlank()) {
Logger.warn("Found blank line in {}", file);
return false;
} else {
return true;
}
}
).map(CommitProcessTime::fromString);
} catch (IOException e) {
// Checked exceptions can't be propagated because the caller of {@code parse} requires
// a method wich doesn't throw any checked exception.
throw new UncheckedIOException(e);
}
}
}