This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 257365 - Conditional breakpoints are extremely slow and they (probably) don't need to be
Summary: Conditional breakpoints are extremely slow and they (probably) don't need to be
Status: NEW
Alias: None
Product: debugger
Classification: Unclassified
Component: Java (show other bugs)
Version: 8.2
Hardware: PC Windows 10 x64
: P3 normal (vote)
Assignee: Martin Entlicher
URL:
Keywords: PERFORMANCE
Depends on:
Blocks:
 
Reported: 2016-01-02 15:28 UTC by _ gtzabari
Modified: 2016-08-18 14:18 UTC (History)
0 users

See Also:
Issue Type: ENHANCEMENT
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description _ gtzabari 2016-01-02 15:28:36 UTC
Product Version: NetBeans IDE Dev (Build 201512240002)
Java: 1.8.0_66; Java HotSpot(TM) 64-Bit Server VM 25.66-b17
Runtime: Java(TM) SE Runtime Environment 1.8.0_66-b17
System: Windows 10 version 10.0 running on amd64; Cp1252; en_CA (nb)
User directory: C:\Users\Gili\AppData\Roaming\NetBeans\dev
Cache directory: C:\Users\Gili\AppData\Local\NetBeans\Cache\dev

I have a strong suspicion that something is wrong with the implementation of conditional breakpoints. The following testcase demonstrates equivalent code running 10,000 times faster when toggling between conditional and non-conditional breakpoints even though the non-conditional breakpoint is still only getting invoked when the condition is true.

Testcase:

1. Create a Java application with the following code:

import java.time.Duration;
import java.time.Instant;
import java.util.Random;

public class ConditionalBreakpoints {

    public static void main(String[] args) {
        Random random = new Random(0);
        Instant start = Instant.now();
        for (int i = 0; i < 10_000; ++i) {
            int value = random.nextInt();
            if (value == 123456) {
                System.out.println("Set a non-conditional breakpoint here");
            }
            assert (value != 123456) : "Set a conditional breakpoint here";
        }
        System.out.println("Duration: " + Duration.between(start, Instant.now()));
    }
}

2. If you run this code you will notice that neither conditional is ever true (neither the println() nor assert never run); however, adding a debugging breakpoint increases the runtime of the application by over 10,000 times.
3. Set a conditional breakpoint on the second println() with condition "value == 123456".
4. Debug project (CTRL+F5). On my machine, runtime is 12 seconds.
5. Delete or disable the breakpoint from step 2. Add a non-conditional breakpoint on the first println().
6. Debug project (CTRL+F5). On my machine, runtime is 1ms.

As you can see, in both cases the breakpoints are only hit when the conditional is true.

Is it possible for Netbeans to implement conditional breakpoints in terms of non-conditional breakpoints as seen above? Perhaps you could rewrite method bytecode on-the-fly to add the conditional directly into the method (with a non-conditional breakpoint) instead of using JPDA if the latter is too slow?

What do you think?
Comment 1 _ gtzabari 2016-01-03 08:07:53 UTC
To clarify, this isn't a theoretical problem I am complaining about. I am attempting to debug Genetic Algorithms code using conditional breakpoints. The code in question gets invokes tens of millions of times per minute (which is quite normal for Genetic Algorithms) and the resulting performance is extremely bad.

If I modify my code and use non-conditional breakpoints, the debugging session flies.

Also, I noticed that my code's concurrency drops like a rock (only one CPU core used when using conditional breakpoints and all cores used without them). Do these breakpoints add some sort of locking that would explain this?
Comment 2 Martin Entlicher 2016-08-18 14:07:39 UTC
This is most probably impossible to implement.
We can patch a method's bytecode, but the changed method will be executed only after a re-enter of the method. Till the method is re-entered, the old bytecode is being executed. And since main() method is never re-entered, I do not see a way how we could make it work.

I'm keeping this as an enhancement though, for that case that https://bugs.openjdk.java.net/browse/JDK-4615046 is implemented.
Comment 3 _ gtzabari 2016-08-18 14:18:03 UTC
Okay. Ignoring bytecode rewriting for a minute, why are conditional breakpoints so much slower than the rewritten code?