speed up debugging a static analysis checker?

Hi,

I’m now having a question of how to speed up startup runs of a static analysis checker in the lldb debugger. It takes about 21 seconds for the debugger to stop at the first breakpoint at the SimpleStreamChecker::checkPreCall function when I run the following command:

lldb-6.0 -- clang-8 -cc1 -analyze -analyzer-checker=alpha.unix.SimpleStream \
 test/Analysis/simple-stream-checks.c

Are there ways to make it faster? I run many debugging sessions not only to figure out how the static analyzer works but also to debug my first checker. Any time saving method is appreciated.

Hi Lou,

You probably want to only debug the analysis running on a function you are interested in.
-Xclang -analyzer-display-progress
shows what functions the analyzer is going through, and
-Xclang -analyze-function “function-name”
let’s you select the function (use the exact name copied from the previous list).

You can also try release+debuginfo configuration if the former is too slow.
20 seconds does sound excessive for a simple test file in any case though, so that is strange.

My simplified test case file only contains one function, with others commented out.

I tried the RelWithDebInfo CMake build type, it slightly reduced the time to reach the first breakpoint from 21 to 16 seconds when I ran it with lldb command line. But when I debug clang in vscode, this configuration doesn’t stop at the breakpoint (with the CodeLLDB extension). The Debug build stops at the breakpoint. Saving 4 seconds on command line is not useful because setting or canceling a breakpoint on the command line takes more time for me in the unfamiliar code base.

I already used gdb-add-index to the clang executable file.

Any other method might help?

How much time does it take you to stop at a breakpoint in a checker?

Hi Lou,

Somehow I haven’t seen your follow up email.
Can you describe a full reproducible example?
With an exact command line invocation, exact input file, and exact breakpoint line.

George

I copied my previous follow-up email below my signature, which you missed. Here’s the full description.

The debugging commands are as follows.

llvm/debug-git$ lldb-6.0 -- bin/clang-8 -cc1 -analyze -analyzer-checker=alpha.unix.SimpleStream ../src-git/tools/clang/test/Analysis/simple-stream-checks.c
(lldb) target create "bin/clang-8"
Current executable set to 'bin/clang-8' (x86_64).
(lldb) settings set -- target.run-args "-cc1" "-analyze" "-analyzer-checker=alpha.unix.SimpleStream" "../src-git/tools/clang/test/Analysis/simple-stream-checks.c"

(lldb) b SimpleStreamChecker.cpp:132
Breakpoint 1: no locations (pending).
WARNING: Unable to resolve breakpoint to any actual locations.

(lldb) run`` <<<<<-------- takes about 21 seconds to hit the breakpoint
Process 26355 launched: '/home/lu/work/git-repos/llvm/debug-git/bin/clang-8' (x86_64)
1 location added to breakpoint 1
Process 26355 stopped
* thread #1, name = 'clang-8', stop reason = breakpoint 1.1
frame #0: 0x00007fffec1f0188 libclangStaticAnalyzerCheckers.so.8svn(anonymous namespace)::SimpleStreamChecker::checkPostCall(this=0x00000000002c0210, Call=0x0000000000335c80, C=0x00007fffffff83a8) const at SimpleStreamChecker.cpp:132 129 return; 130 131 // Generate the next transition (an edge in the exploded graph). → 132 ProgramStateRef State = C.getState(); 133 State = State->set(FileDesc, StreamState::getOpened()); 134 C.addTransition(State); 135 }`

where clang-8 is built by using the following CMake configuration (and make clang):

cmake -G "Unix Makefiles" -DLLVM_OPTIMIZED_TABLEGEN=true -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON ../src-git/ -DLLVM_USE_LINKER=lld-6.0 -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLLVM_TARGETS_TO_BUILD=""

That’s weird.
It takes about 1-2 seconds for me.

I copied my previous follow-up email below my signature, which you missed. Here’s the full description.

The debugging commands are as follows.

llvm/debug-git$ lldb-6.0 -- bin/clang-8 -cc1 -analyze -analyzer-checker=alpha.unix.SimpleStream ../src-git/tools/clang/test/Analysis/simple-stream-checks.c
(lldb) target create "bin/clang-8"
Current executable set to 'bin/clang-8' (x86_64).
(lldb) settings set -- target.run-args "-cc1" "-analyze" "-analyzer-checker=alpha.unix.SimpleStream" "../src-git/tools/clang/test/Analysis/simple-stream-checks.c"

(lldb) b SimpleStreamChecker.cpp:132
Breakpoint 1: no locations (pending).
WARNING: Unable to resolve breakpoint to any actual locations.

This is also weird. If lldb replies with “Unable to resolve breakpoint”, it means that, well, it could not resolve the breakpoint.
And yet it does stop at a breakpoint (much) later on.

Maybe try a simpler cmake invocation? You customize quite a few things, try just having no customizations at all.
You write that you have used gdb-add-index, but you should not have to use it.

That’s weird.
It takes about 1-2 seconds for me.

Wow, this is awesome! What’s your machine’s configuration and system?

(lldb) b SimpleStreamChecker.cpp:132
Breakpoint 1: no locations (pending).
WARNING: Unable to resolve breakpoint to any actual locations.

This is also weird. If lldb replies with “Unable to resolve breakpoint”, it means that, well, it could not resolve the breakpoint.
And yet it does stop at a breakpoint (much) later on.

My build uses dynamically linked libraries, and the symbol is not available when the related library isn’t loaded.

When I use the default build which uses statically linked libraries, it becomes much slower, with a huge clang program that is 1.5G without a machine target.

That’s weird.
It takes about 1-2 seconds for me.

Wow, this is awesome! What’s your machine’s configuration and system?

Not-very-powerful iMac.

(lldb) b SimpleStreamChecker.cpp:132
Breakpoint 1: no locations (pending).
WARNING: Unable to resolve breakpoint to any actual locations.

This is also weird. If lldb replies with “Unable to resolve breakpoint”, it means that, well, it could not resolve the breakpoint.
And yet it does stop at a breakpoint (much) later on.

My build uses dynamically linked libraries, and the symbol is not available when the related library isn’t loaded.

I think that is your problem.

When I use the default build which uses statically linked libraries, it becomes much slower, with a huge clang program that is 1.5G without a machine target.

Is 1.5GB a problem though?
In my experience “gold” linker on Linux should be performant enough.

(lldb) b SimpleStreamChecker.cpp:132
Breakpoint 1: no locations (pending).
WARNING: Unable to resolve breakpoint to any actual locations.

This is also weird. If lldb replies with “Unable to resolve breakpoint”, it means that, well, it could not resolve the breakpoint.
And yet it does stop at a breakpoint (much) later on.

My build uses dynamically linked libraries, and the symbol is not available when the related library isn’t loaded.

I think that is your problem.

Any idea on how to fix it?

When I use the default build which uses statically linked libraries, it becomes much slower, with a huge clang program that is 1.5G without a machine target.

Is 1.5GB a problem though?
In my experience “gold” linker on Linux should be performant enough.

I’m not sure. But it takes more than 30s to hit the breakpoint with the statically linked library.

Hi Lou,

I find it easiest to just follow the guide at

https://llvm.org/docs/GettingStarted.html#for-developers-to-work-with-a-git-monorepo

specify the projects you need (probably “clang;libcxx;libcxxabi”), set the linker to gold and not customize anything else.
If you do that, do you still hit the slowdown?

George

I tried that git monorepo method, but got the same slowdown about 21 seconds as before with either gold or lldb and dynamic linking. It’s still slower with the default static linking.