Advanced code editor markup, call stack UI, and multithreaded debugging tools — in a new plugin for RAD Studio now freely available.
We’re very pleased to announce a new IDE extension available today for RAD Studio 10.4.1, created by the same author as the popular Bookmarks and Navigator plugins, Parnassus. If you’re reading this, it’s already available in GetIt for anyone with Update Subscription: simply open GetIt, go to the IDE Plugins section, and install the ‘Parallel Debugger’. It requires Delphi or C++Builder 10.4.1 or newer.
What is it?
- Supercharged debugger
- Special features for debugging multithreaded apps
- … that also helps to debug traditional single-threaded apps!
Something for everyone. Read on for more!
Table of Contents
If you have more than one thread in your application, you’ve probably wanted to debug thread interaction. A traditional IDE’s view of a debugged app, while it might list multiple threads in a Threads view, is to treat the app as though it has only a single thread: you will see only one call stack, and the run/pause/step controls are for the entire process. This leaves you, a developer who has to debug your app, with questions like:
- How do I see if multiple threads are running in the same code at once?
- How do I see what all my threads are doing at any one time?
- How do I step through a method in just one thread?
Ie, how do I debug one thread without other threads running and executing code I don’t want them to, hitting breakpoints, etc?
- How much CPU is each of my threads using? Are they efficient?
And perhaps other questions or wishes, even debugging just in a single thread, like:
- I wish it was easy to see all the methods in the call stack highlighted in my code
- I wish I could easily make a breakpoint only apply to a particular thread
- I wish the editor markup showing the current line of code looked a bit more obvious
- I wish, when pausing the process, it didn’t take me to the CPU view but would show me only my own source
Every one of these is answered by this new plugin.
Let’s run through its features. In the next section, you’ll read about the Parallel Threads view and parallel call stacks; per-thread running and stepping; the Process view; new editor markup including threads and call stacks in the editor; setting a breakpoint’s thread affinity; moving current execution; the new Thread main menu; and more…
The Parallel Threads view
View > Debug Windows > Parallel Threads
This window lists all threads in the process, listed horizontally. When your app is running, if it’s on Windows each thread has a chart displaying its CPU usage.
When the app is paused, each thread displays its call stack.
- Every thread is assigned a unique colour, starting with a medium blue for the application’s main thread. This colour is used as a visual guide to identifying the thread everywhere.
- Thread names are displayed. Even if you don’t name your main thread, Parallel Debugger is smart enough to detect it.
- The current thread is bolded and has a thin border of its colour around it. Double-click the title of a thread (its name) to make it the current thread.
- Call stack entries without source code – ie, not debuggable without using the CPU view – are collapsed by default. You can expand these (or turn it off to show a traditional call stack.)
When pausing the process, the debugger will always show the top debuggable call stack entry. That is, it might not show the top entry in the call stack the way the IDE traditionally does, but it will show the source code of yours that calls into it. The idea here is to debug what you have control over – always show the source.
The leftmost button in each thread toolbar pauses the whole process, making that thread the current thread. It is ‘pause the process in this thread’. The rightmost button lets you change the order threads are displayed, by pinning threads to the left or next to another pinned thread. This is useful when you have many threads in your app, and you want to keep the ones you’re interested in grouped together. If a pinned thread has a name, pinning is persistent across process restarts: when you terminate and restart your app, the same threads will be pinned.
Running or Stepping a Single Thread
The remaining toolbar buttons are for thread run control.
The IDE’s normal run, step over, step into, etc controls are process-level; that is, they will run the entire process, waking all threads, and you just hope that nothing else happens until the step-over operation is complete in the thread you’re looking at. In practice, lots can – exceptions, breakpoints, etc – plus of course, sometimes you just want to make sure other threads don’t run while debugging a single thread.
- Run only this thread, keeping all other threads paused
- Keep this thread paused, but run all other threads
- Step into a method, in this thread only
- Step over a line of code, in this thread only. This allows only this thread to run and step; no other threads are allowed to run at the same time
- Run until method return, for this thread only
To use these, make sure the thread you’re interested in is the current thread, by double-clicking its title or name. You will see it draws its title in bold.
Each of these has a keyboard shortcut, meaning you can step (etc) via the keyboard not just by clicking a button with the mouse. Shortcuts are visible in the Thread menu which has menu items for the current thread (see below.)
Per-thread run control is one of the most powerful features in the Parallel Debugger.
One important task when understanding what’s happening in a multithreaded application is knowing when multiple threads are executing in the same area of code. The Parallel Debugger makes this clear through adding markup in the editor for every thread’s full call stack. These are shown via ‘tags’, small coloured markers on the right-hand side of the editor.
The top call stack entry – that is, where the thread is executing ‘now’ – is marked with a solid-colour tag, using the thread colour. Other call stack entries for the same thread are in a faded version of the thread colour (noting the thread is still marked with a solid circle in the tag.)
This lets you quickly read your code and know, ‘Thread X is executing somewhere inside this line of code’ and ‘Thread Y and Thread Z are both in the same method right now’. You will even see where the threads are exactly. In this screenshot, the current thread is the blue one, and a second thread (light red) is executing with its current execution point inside IsPrime(), but the call to IsPrime highlighted the line above the current thread’s execution point.
Before installing the plugin, the IDE used to display the current thread’s execution point with a small blue arrow. That is now replaced with a large chevron on the left hand side of the code editor.
You can change where the execution point is – where the thread will start executing from the next time you hit Run or Step – simply by clicking and dragging this marker.
Breakpoint Thread Affinity
By default, breakpoints apply to all threads. Before installing the plugin, breakpoints were drawn using a red dot, but with the Parallel Debugger, threads are given colours, and red means the red thread. Breakpoints that apply to all threads are now drawn as a multicoloured wheel.
To make a breakpoint apply to only a specific thread, right-click the breakpoint. The new Breakpoint menu lets you choose a thread that the breakpoint will apply to.
Here, this breakpoint only applies to the green thread.
The Process view
View > Debug Windows > Process
This window shows information about the process as a whole. It displays process-level CPU usage (again split into kernel and user-mode), the type of process (eg Wow64), and has run/pause/reset, etc buttons. These are process-level, ie provide the same functionality as the IDE’s own run toolbar.
You can also see a list of threads by clicking the button at the bottom, as a quick way to choose the current thread (since scrolling horizontally in the Threads view can take longer if you have many threads.)
The Thread main menu
The IDE now has a Thread menu, located to the right of the Run menu. This provides a menu for most of the direct operations you can perform for a thread. It lets you set the thread of interest (that is, the current thread if the process is paused, or the thread you want to become the current thread next time you pause), and for the current thread has menu items for thread run control. You can see shortcuts on these menu items.
It also lists each thread in the app, and for each one shows you run control plus pinning, effectively the same features as in the Parallel Threads view.
Finally, the very top menu item controls the Parallel Debugger’s feature level: what it does when your app is running. The lowest level is just to track CPU usage: use this if you want the parallel debugger to be installed, but you don’t want to actively use it for this app currently. The next two levels control how deeply the debugger tracks thread call stacks.
Use this if you have dozens or hundreds of threads. In this situation, you’re likely only interested in a subset of threads. Set the feature level to ‘Selected Call Stacks Only’, and the parallel debugger will track call stacks for the main thread, pinned threads, and the current thread only by default. You can always get the call stack for any thread by clicking a button displayed over the call stack area in the Threads view.
The Parallel Debugger has full functionality when locally debugging apps on Windows.
On other platforms, or remote debugging, functionality depends on what the debugger supports. CPU usage is only supported for local (non-remote debugging) Windows apps. Per-thread stepping or running will only function on platforms that support thread freezing. There is a known issue for C++ Win64 where call stacks can not be evaluated: this will be fixed in an upcoming C++Builder release.
Following a Parnassus tradition started with Bookmarks, the Parallel Debugger actually solves a bug! (RSP-29768.)
In general: if you’re using Windows, the debugger has full functionality.
The plugin supports RAD Studio 10.4.1 (and newer, when 10.4.2 comes out.)
Getting the Parallel Debugger
The Parallel Debugger is in GetIt now!
Thanks to Embarcadero, Parnassus is making the debugger freely available to any RAD Studio customer with an active update subscription. Open GetIt, go to the IDE Plugins category and click Install.
Both Parnassus and Embarcadero hope you’ll find this extension a great addition to your IDE.
On a personal note, I’d like to thank Embarcadero for being interested in the plugin and wanting to add it to GetIt, and to all my beta testers who have used various versions of this plugin of slowly increasing quality since August. Thank you very much to everyone!