0

I'm writing a test application that displays an A* search in action, and it's running really slow. I profiled it using VisualVM, and got the following results:

enter image description here

Note that the third entry is a lambda containing some long-running code.

The problem is, I can't find a lambda with such a signature anywhere.

Is there any way for me to find out what lambda it's referring to?

Here is pacmanTest.FrontierVisual.java:

package pacmanTest;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import utils.Duple;
import utils.MainLoop;

public class FrontierVisual
        extends Application {

    private Stage stage;
    private Scene scene;

    private final int areaWidth = 800;
    private final int areaHeight = 800;

    private final double drawScale = 15;

    private Canvas canvas = new Canvas(800, 800);
    private GraphicsContext gc = canvas.getGraphicsContext2D();

    private final MapArea<Wall> area = new MapArea<>(areaWidth, areaHeight);


    private static List<Duple<Integer>> cellsAround(Duple<Integer> pos, List<Duple<Integer>> offsets) {
        List<Duple<Integer>> surroundingCells = new ArrayList<>();

        offsets.stream()
            .map( offset -> pos.map(offset, (x1, x2) -> x1 + x2) )
            .forEach(surroundingCells::add);

        return surroundingCells;
    }

    private void drawSquare(Duple<Integer> position, Color color) {
        gc.setFill(color);
        gc.fillRect(position.getX() * drawScale, position.getY() * drawScale, drawScale, drawScale);
    }

    @Override
    public void start(Stage stage) throws Exception {
        this.stage = stage;

        BorderPane rootNode = new BorderPane();

        scene = new Scene(rootNode);
        stage.setScene(scene);

        rootNode.setCenter(canvas);

        Duple<Integer> startPos = new Duple<Integer>(20, 20);
        Duple<Integer> goalPos = new Duple<Integer>(30, 30);

        Wall wall = new SolidWall();

        /*for (int d = 29; d <= 41; d++) {
            int e = d / 2;
            area.setCellAt(d, e, wall);
        }*/

        area.setCellAt(19, 32, wall);
        area.setCellAt(20, 31, wall);
        area.setCellAt(21, 30, wall);
        area.setCellAt(22, 29, wall);
        area.setCellAt(23, 28, wall);
        area.setCellAt(24, 27, wall);
        area.setCellAt(25, 26, wall);
        area.setCellAt(26, 25, wall);
        area.setCellAt(27, 24, wall);
        area.setCellAt(28, 23, wall);
        area.setCellAt(29, 22, wall);
        area.setCellAt(30, 21, wall);
        area.setCellAt(31, 20, wall);
        area.setCellAt(32, 19, wall);

        Deque<Duple<Integer>> frontier = new ArrayDeque<>();
        Map<Duple<Integer>, Duple<Integer>> cameFrom = new HashMap<>();
        cameFrom.put(startPos, startPos);

        frontier.push(startPos);

        final List<Duple<Integer>> fourDirectionOffsets = Collections.unmodifiableList(Arrays.asList(
            new Duple<Integer>(1,0), new Duple<Integer>(-1,0), new Duple<Integer>(0,1), new Duple<Integer>(0,-1) ));

        MainLoop mainLoop = new MainLoop(10000, t -> {
            utils.Utils.clearCanvas(gc);

            gc.setFill(Color.STEELBLUE);

            Duple<Integer> poppedLocation = frontier.pop();

            drawSquare(startPos, Color.BLACK);
            drawSquare(goalPos, Color.GREEN);

            List<Duple<Integer>> neighbors = cellsAround(poppedLocation, fourDirectionOffsets);

            neighbors.stream()
                .filter(location -> !cameFrom.containsKey(location) && area.cellIsInBounds(location) && area.getCellAt(location) == null)
                .forEach( neighbor -> {
                    frontier.add(neighbor);
                    cameFrom.put(neighbor, poppedLocation);

                    drawSquare(neighbor, Color.CORAL);
            });

            frontier.stream()
            .forEach( frontierPos -> {
                drawSquare(frontierPos, Color.BLUE);
            });

            reconstructPath(cameFrom, startPos, goalPos).stream()
                .forEach( pathPos -> {
                    if (pathPos != startPos && area.getCellAt(pathPos) == null) {
                        drawSquare(pathPos, Color.ORANGE);
                    }
            });

            area.forallNonEmptyCells( (pos, contents) -> {
                drawSquare(pos, Color.CHOCOLATE);
            });


        });

        mainLoop.start();

        stage.show();

    }

    private static List<Duple<Integer>> reconstructPath(Map<Duple<Integer>, Duple<Integer>> cameFrom, Duple<Integer> start, Duple<Integer> goal) {
        List<Duple<Integer>> path = new ArrayList<>();
        path.add(goal);

        Duple<Integer> current = goal;

        do {
            path.add(current);

            current = cameFrom.get(current);

        } while (current != null && !current.equals(start));

        Collections.reverse(path);

        return path;
    }

    public static void main(String[] args) {
        launch(args);
    }

}

Any ideas here would be appreciated.

Side note: If anyone knows how to reduce the drawing time of JavaFX's canvas, that would be awesome given it's the biggest CPU hog.

Carcigenicate
  • 43,494
  • 9
  • 68
  • 117

1 Answers1

1

Well this is your lambda$1 expression because of the "parameter list". This part is the only one which uses a Deque, 2 x Duple, List, Map, Long:

new MainLoop(10000, /* THIS -> */ t -> { ... });

BTW don't do any filtering actions in a Stream in the forEach method. Therefore use the Stream::filter.

Here:

reconstructPath(cameFrom, startPos, goalPos).stream()
          .filter(pathPos != startPos && area.getCellAt(pathPos) == null)
          .forEach(pathPos -> drawSquare(pathPos, Color.ORANGE));
Flown
  • 11,480
  • 3
  • 45
  • 62
  • How do you know that's lambda1? It has a different set of arguments than what the profiler says. And I'm not sure what you mean by the second part. I am using `Stream::filter`. – Carcigenicate Oct 19 '15 at 13:26
  • Ahh, I see. Good point. I still don't see how the main loop is the Lambda that it's talking about though; it only takes a `long` and a `Consumer`. Is everything captured by the Lambda included behind the scenes? – Carcigenicate Oct 19 '15 at 13:59
  • I think this link will help you [Translation of Lambda Expressions](http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html) – Flown Oct 19 '15 at 14:02