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

Extremely slow compilation for pattern matching instanceof method #2328

Closed
j-baker opened this issue Jul 25, 2022 · 6 comments
Closed

Extremely slow compilation for pattern matching instanceof method #2328

j-baker opened this issue Jul 25, 2022 · 6 comments

Comments

@j-baker
Copy link
Contributor

j-baker commented Jul 25, 2022

What happened?

I wrote code which looks roughly like:

        @SuppressWarnings("CyclomaticComplexity")
        private static long getRoutingId(BlockId block) {
            if (block instanceof RDDBlockId b) {
                return b.rddId();
            } else if (block instanceof ShuffleBlockId b) {
                return b.shuffleId();
            } else if (block instanceof ShuffleBlockBatchId b) {
                return b.shuffleId();
            } else if (block instanceof ShuffleBlockChunkId b) {
                return b.shuffleId();
            } else if (block instanceof ShuffleDataBlockId b) {
                return b.shuffleId();
            } else if (block instanceof ShuffleIndexBlockId b) {
                return b.shuffleId();
            } else if (block instanceof ShuffleChecksumBlockId b) {
                return b.shuffleId();
            } else if (block instanceof ShufflePushBlockId b) {
                return b.shuffleId();
            } else if (block instanceof ShuffleMergedBlockId b) {
                return b.shuffleId();
            } else if (block instanceof ShuffleMergedDataBlockId b) {
                return b.shuffleId();
            } else if (block instanceof ShuffleMergedIndexBlockId b) {
                return b.shuffleId();
            } else if (block instanceof ShuffleMergedMetaBlockId b) {
                return b.shuffleId();
            } else if (block instanceof BroadcastBlockId b) {
                return b.broadcastId();
            } else {
                throw new SafeIllegalStateException("unhandled");
            }

where the underlying type of BlockId is a Scala case class with many subtypes. Not my favourite code, but surely close to as good as can be done.

Compilation is currently 9 minutes in. Stack traces are implying that the expensive code relates to the Safety Propagation code. JFR can be provided on request.

What did you want to happen?

Compilation in a reasonable amount of time.

@j-baker
Copy link
Contributor Author

j-baker commented Jul 25, 2022

Additional note: commenting out most of the cases causes compilation to complete in seconds, and compilation is rapid when run from IDE (aka no error-prone).

@j-baker
Copy link
Contributor Author

j-baker commented Jul 25, 2022

Further additional note: This is definitely to do with the Java 15 feature. Representing the above code as

  private static long getRoutingId(BlockId block) {
            if (block instanceof RDDBlockId) {
                return ((RDDBlockId) block).rddId();
            } else if (block instanceof ShuffleBlockId) {
                return ((ShuffleBlockId) block).shuffleId();
            } else if (block instanceof ShuffleBlockBatchId) {
                return ((ShuffleBlockBatchId) block).shuffleId();
            } else if (block instanceof ShuffleBlockChunkId) {
                return ((ShuffleBlockChunkId) block).shuffleId();
            } else if (block instanceof ShuffleDataBlockId) {
                return ((ShuffleDataBlockId) block).shuffleId();
            } else if (block instanceof ShuffleIndexBlockId) {
                return ((ShuffleIndexBlockId) block).shuffleId();
            } else if (block instanceof ShuffleChecksumBlockId) {
                return ((ShuffleChecksumBlockId) block).shuffleId();
            } else if (block instanceof ShufflePushBlockId) {
                return ((ShufflePushBlockId) block).shuffleId();
            } else if (block instanceof ShuffleMergedBlockId) {
                return ((ShuffleMergedBlockId) block).shuffleId();
            } else if (block instanceof ShuffleMergedDataBlockId) {
                return ((ShuffleMergedDataBlockId) block).shuffleId();
            } else if (block instanceof ShuffleMergedIndexBlockId) {
                return ((ShuffleMergedIndexBlockId) block).shuffleId();
            } else if (block instanceof ShuffleMergedMetaBlockId) {
                return ((ShuffleMergedMetaBlockId) block).shuffleId();
            } else if (block instanceof BroadcastBlockId) {
                return ((BroadcastBlockId) block).broadcastId();
            } else {
                throw new SafeIllegalStateException("unhandled", SafeArg.of("block", block));
            }
        }

compiles as expected

@schlosna
Copy link
Contributor

schlosna commented Jul 25, 2022

I'm curious to see the JFRs and also curious if you tried the JEP 406 pattern matching and how that behaved:

private static long getRoutingId(BlockId block) {
    return switch (block) ->
        case RDDBlockId b -> b.rddId();
        case ShuffleBlockId b -> b.shuffleId();
        case ShuffleBlockBatchId b -> b.shuffleId();
        case ShuffleBlockChunkId b -> b.shuffleId();
        case ShuffleDataBlockId b -> b.shuffleId();
        case ShuffleIndexBlockId b -> b.shuffleId();
        case ShuffleChecksumBlockId b -> b.shuffleId();
        case ShufflePushBlockId b -> b.shuffleId();
        case ShuffleMergedBlockId b -> b.shuffleId();
        case ShuffleMergedDataBlockId b -> b.shuffleId();
        case ShuffleMergedIndexBlockId b -> b.shuffleId();
        case ShuffleMergedMetaBlockId b -> b.shuffleId();
        case BroadcastBlockId b -> b.broadcastId();
        default -> throw new SafeIllegalStateException("unhandled");
    };

@carterkozak
Copy link
Contributor

switch expressions aren't fully supported at this point, as the the language feature is relatively new, and our data-flow framework can't be terribly helpful. On my list to implement some bridging, but it's relatively low priority at the moment.

@carterkozak
Copy link
Contributor

I see the issue in this case, the dataflow framework doesn't know how to follow a pattern matching statement, and assumes variables are defined elsewhere. In verifying that, it's doing a fairly expensive operation. Ideally I can provide the correct context, otherwise I'll put something together so that it doesn't make builds hang in the interim

@carterkozak
Copy link
Contributor

#2328 should do the trick, though I may need to poke the build a bit if running all the tests on java 17 doesn't work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants