Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #344: add multi-thread support to CheckstyleReportsParser #514

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,6 @@ public final class Main {
+ "if this folder exists its content will be purged;\n"
+ "\t-h - simply shows help message.";

/**
* Number of "file" xml tags parsed at one iteration of parser.
*/
public static final int XML_PARSE_PORTION_SIZE = 50;

/**
* Name for the site file.
*/
Expand Down Expand Up @@ -162,7 +157,7 @@ public static void main(final String... args) throws Exception {
// XML parsing stage
System.out.println("XML parsing is started.");
diffReport = CheckstyleReportsParser.parse(paths.getBaseReportPath(),
paths.getPatchReportPath(), XML_PARSE_PORTION_SIZE);
paths.getPatchReportPath());
}
else {
// file parsing stage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import com.github.checkstyle.parser.CheckstyleReportsParser;

Expand All @@ -38,6 +44,9 @@
*/
public final class DiffReport {

/** Number of records to process at a time when looking for differences. */
private static final int SPLIT_SIZE = 100;

/**
* Container for parsed data,
* note it is a TreeMap for memory keeping purposes.
Expand All @@ -63,6 +72,22 @@ public Statistics getStatistics() {
return statistics;
}

/**
* Utility to merge the patch related contents of the {@code other} class to the current.
*
* @param other The other class to merge.
*/
public void mergePatch(DiffReport other) {
mergeRecords(other.records);
statistics.copyPatch(other.statistics);
}

private void mergeRecords(Map<String, List<CheckstyleRecord>> other) {
for (Entry<String, List<CheckstyleRecord>> item : other.entrySet()) {
addRecords(item.getValue(), item.getKey());
}
}

/**
* Adds new records to the diff report,
* when there are records with this filename, comparison
Expand Down Expand Up @@ -103,16 +128,44 @@ public void addRecords(List<CheckstyleRecord> newRecords,
*/
private static List<CheckstyleRecord> produceDiff(
List<CheckstyleRecord> list1, List<CheckstyleRecord> list2) {
final List<CheckstyleRecord> diff;
try {
diff = produceDiffEx(list1, list2);
diff.addAll(produceDiffEx(list2, list1));
}
catch (InterruptedException | ExecutionException ex) {
throw new IllegalStateException("Multi-threading failure reported", ex);
}

return diff;
}

private static List<CheckstyleRecord> produceDiffEx(
List<CheckstyleRecord> list1, List<CheckstyleRecord> list2)
throws InterruptedException, ExecutionException {
final List<CheckstyleRecord> diff = new ArrayList<>();
for (CheckstyleRecord rec1 : list1) {
if (!isInList(list2, rec1)) {
diff.add(rec1);
if (list1.size() < SPLIT_SIZE) {
for (CheckstyleRecord rec1 : list1) {
if (!isInList(list2, rec1)) {
diff.add(rec1);
}
}
}
for (CheckstyleRecord rec2 : list2) {
pbludov marked this conversation as resolved.
Show resolved Hide resolved
if (!isInList(list1, rec2)) {
diff.add(rec2);
else {
final ExecutorService executor =
Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
final List<Future<List<CheckstyleRecord>>> futures = new ArrayList<>();
final int size = list1.size();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks as hardcoded

    private static List<CheckstyleRecord> produceDiff(
            List<CheckstyleRecord> list1, List<CheckstyleRecord> list2) {
        return Stream.concat(
                StreamSupport.stream(list1.spliterator(), SPLIT_SIZE <= list1.size())
                    .filter(rec -> !isInList(list2, rec)),
                StreamSupport.stream(list2.spliterator(), SPLIT_SIZE <= list2.size())
                    .filter(rec -> !isInList(list1, rec))
            )
            .collect(Collectors.toList());
    }

Copy link
Member Author

@rnveach rnveach Oct 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this support multi-threading? The whole issue is we need this multi-threaded to reduce processing time looping through the 2 lists. If everything is processed in 1 thread then there is no time saving.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StreamSupport.stream(list1.spliterator(), SPLIT_SIZE <= list1.size()) is basically list1.stream() if the size is less then SPLIT_SIZE. Otherwise it is list1.parallelStream()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not familar with streams but I assume parallel is multi-threaded. I will compare and see how they stack against each other.

for (int i = 0; i < size; i += SPLIT_SIZE) {
futures.add(executor.submit(new MultiThreadedDiff(list1, list2, i, Math.min(size, i
+ SPLIT_SIZE))));
}

for (Future<List<CheckstyleRecord>> future : futures) {
diff.addAll(future.get());
}

executor.shutdown();
}
return diff;
}
Expand Down Expand Up @@ -141,7 +194,7 @@ private static boolean isInList(List<CheckstyleRecord> list,
/**
* Generates statistical information and puts in in the accumulator.
*/
public void getDiffStatistics() {
public void generateDiffStatistics() {
statistics.setFileNumDiff(records.size());
for (Map.Entry<String, List<CheckstyleRecord>> entry
: records.entrySet()) {
Expand Down Expand Up @@ -183,4 +236,46 @@ public int compare(final CheckstyleRecord arg0,
}
}

/** Separate class to multi-thread 2 lists checking if items from 1 is in the other. */
private static final class MultiThreadedDiff implements Callable<List<CheckstyleRecord>> {
/** First list to examine. */
private List<CheckstyleRecord> list1;
/** Second list to examine. */
private List<CheckstyleRecord> list2;
/** Inclusive start position of the first list. */
private int list1Start;
/** Non-inclusive End position of the first list. */
private int list1End;

/**
* Default constructor.
*
* @param list1 First list to examine.
* @param list2 Second list to examine.
* @param list1Start Inclusive start position of the first list.
* @param list1End Non-inclusive End position of the first list.
*/
private MultiThreadedDiff(List<CheckstyleRecord> list1, List<CheckstyleRecord> list2,
int list1Start, int list1End) {
this.list1 = list1;
this.list2 = list2;
this.list1Start = list1Start;
this.list1End = list1End;
}

@Override
public List<CheckstyleRecord> call() throws Exception {
final List<CheckstyleRecord> diff = new ArrayList<>();

for (int i = list1Start; i < list1End; i++) {
final CheckstyleRecord rec1 = list1.get(i);

if (!isInList(list2, rec1)) {
diff.add(rec1);
}
}
return diff;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,18 @@ public final Map<String, BigInteger> getSeverityNumDiff() {
return severityNumDiff;
}

/**
* Utility to merge the patch related contents of the {@code other} class to the current.
*
* @param other The other class to merge.
*/
public void copyPatch(Statistics other) {
severityNumPatch = other.severityNumPatch;
moduleNumPatch = other.moduleNumPatch;
fileNumPatch = other.fileNumPatch;
uniqueMessagesPatch = other.uniqueMessagesPatch;
}

/**
* Getter for total number of severity records for difference.
*
Expand Down
Loading