Ticket #17819: 17819-multi-thread.patch

File 17819-multi-thread.patch, 5.5 KB (added by GerdP, 5 years ago)

backport from MultipolygonBuilder

  • src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java

     
    1616import java.util.Map;
    1717import java.util.Map.Entry;
    1818import java.util.Set;
     19import java.util.concurrent.ForkJoinPool;
     20import java.util.concurrent.ForkJoinTask;
     21import java.util.concurrent.RecursiveTask;
    1922
    2023import org.openstreetmap.josm.command.ChangeCommand;
    2124import org.openstreetmap.josm.command.Command;
     
    3841import org.openstreetmap.josm.tools.Geometry;
    3942import org.openstreetmap.josm.tools.Geometry.PolygonIntersection;
    4043import org.openstreetmap.josm.tools.Logging;
     44import org.openstreetmap.josm.tools.Utils;
    4145
    4246/**
    4347 * Checks if multipolygons are valid
     
    4448 * @since 3669
    4549 */
    4650public class MultipolygonTest extends Test {
     51    private static final ForkJoinPool THREAD_POOL = newForkJoinPool();
    4752
     53    private static ForkJoinPool newForkJoinPool() {
     54        try {
     55            return Utils.newForkJoinPool(
     56                    "multipolygon_creation.numberOfThreads", "multipolygon-test-%d", Thread.NORM_PRIORITY);
     57        } catch (SecurityException e) {
     58            Logging.log(Logging.LEVEL_ERROR, "Unable to create new ForkJoinPool", e);
     59            return null;
     60        }
     61    }
     62
    4863    /** Non-Way in multipolygon */
    4964    public static final int WRONG_MEMBER_TYPE = 1601;
    5065    /** No useful role for multipolygon member */
     
    461476     * @param sharedNodes all nodes shared by multiple ways of this multipolygon
    462477     */
    463478    private void checkRoles(Relation r, List<PolyData> allPolygons, Map<Long, RelationMember> wayMap, Set<Node> sharedNodes) {
    464         PolygonLevelFinder levelFinder = new PolygonLevelFinder(sharedNodes);
    465         List<PolygonLevel> list = levelFinder.findOuterWays(allPolygons);
     479        List<PolygonLevel> list = findOuterWaysMultiThread(allPolygons, sharedNodes);
    466480        if (list == null || list.isEmpty()) {
    467481            return;
    468482        }
     
    796810    }
    797811
    798812    /**
     813     * Collects outer way and corresponding inner ways from all rings.
     814     * @param rings the polygon rings
     815     * @param sharedNodes all nodes shared by multiple ways of this multipolygon
     816     * @return list of nesting levels
     817     */
     818    private static List<PolygonLevel> findOuterWaysMultiThread(List<PolyData> rings, Set<Node> sharedNodes) {
     819        PolygonLevelFinder worker = new PolygonLevelFinder(sharedNodes, rings, 0, rings.size(),
     820                new ArrayList<PolygonLevel>(), 128);
     821        if (THREAD_POOL != null) {
     822            return THREAD_POOL.invoke(worker);
     823        } else {
     824            return worker.computeDirectly();
     825        }
     826    }
     827
     828    /**
    799829     * Find nesting levels of polygons. Logic taken from class MultipolygonBuilder, uses different structures.
    800830     */
    801     private static class PolygonLevelFinder {
    802         private final Set<Node> sharedNodes;
     831    private static class PolygonLevelFinder extends RecursiveTask<List<PolygonLevel>> {
     832        private final transient Set<Node> sharedNodes;
     833        private final transient List<PolyData> input;
     834        private final int from;
     835        private final int to;
     836        private final transient List<PolygonLevel> output;
     837        private final int directExecutionTaskSize;
    803838
    804         PolygonLevelFinder(Set<Node> sharedNodes) {
     839        private static final long serialVersionUID = 0;
     840
     841        PolygonLevelFinder(Set<Node> sharedNodes, List<PolyData> input, int from, int to, List<PolygonLevel> output,
     842                int directExecutionTaskSize) {
    805843            this.sharedNodes = sharedNodes;
     844            this.input = input;
     845            this.from = from;
     846            this.to = to;
     847            this.output = output;
     848            this.directExecutionTaskSize = directExecutionTaskSize;
    806849        }
    807850
    808         List<PolygonLevel> findOuterWays(List<PolyData> allPolygons) {
    809             return findOuterWaysRecursive(0, allPolygons);
    810         }
    811 
    812851        private List<PolygonLevel> findOuterWaysRecursive(int level, List<PolyData> polygons) {
    813852            final List<PolygonLevel> result = new ArrayList<>();
    814853
     
    906945            }
    907946            return null;
    908947        }
     948
     949        @Override
     950        protected List<PolygonLevel> compute() {
     951            if (to - from <= directExecutionTaskSize) {
     952                return computeDirectly();
     953            } else {
     954                final Collection<ForkJoinTask<List<PolygonLevel>>> tasks = new ArrayList<>();
     955                for (int fromIndex = from; fromIndex < to; fromIndex += directExecutionTaskSize) {
     956                    tasks.add(new PolygonLevelFinder(sharedNodes, input, fromIndex, Math.min(fromIndex + directExecutionTaskSize, to),
     957                            new ArrayList<PolygonLevel>(), directExecutionTaskSize));
     958                }
     959                for (ForkJoinTask<List<PolygonLevel>> task : ForkJoinTask.invokeAll(tasks)) {
     960                    List<PolygonLevel> res = task.join();
     961                    if (res == null) {
     962                        return null;
     963                    }
     964                    output.addAll(res);
     965                }
     966                return output;
     967            }
     968        }
     969
     970        List<PolygonLevel> computeDirectly() {
     971            for (int i = from; i < to; i++) {
     972                processOuterWay(0, input, output, input.get(i));
     973            }
     974            return output;
     975        }
    909976    }
    910977
    911978    /**