Lori Matassa and Max Domeika are the authors of Break Away with Intel Atom Processors: A Guide to Architecture Migration
The key difference between debugging on single-core and multi-core systems is in the distribution of the program execution onto multiple cores. The application or system code developer must be aware which pieces of code are executing on each processor core. Another question to consider: are all cores sharing a common memory map or are the memory locations different? If program flow relies upon cached data, then it is important to understand which cache levels are shared between the different processor cores and which ones are not.
Furthermore, how does the code takes advantage of the parallel execution power offered by the multi-core platform? Parallelism could be implemented on a process level or on a thread level. The software workload could be partitioned to the different processor cores based upon functional blocks or logical blocks. Alternatively, partitioning could involve executing the same code on all cores, but operating on different data sets.
The impacts of multi-core processors on the debugger are several fold. First and foremost, execution control and breakpoint handling has an additional layer of complexity. In addition to knowing which memory address or data value dependency a breakpoint has, the debugger now also needs to track the association of processor core, OS thread, or application thread with individual breakpoints. Thread management and core affinity management is generally handled by the OS which implies that for application debug purposes it will be important to track the OS thread identifier for each application thread synchronized with the memory location.
Second, debugging a heavily multithreaded application in a debugger that lacks thread awareness can be a challenge. For example, if a breakpoint is set while executing in the context of one thread, there is a risk that the breakpoint is reached by another thread, thus preventing effective debug of the execution flow of your thread.
A debugger that supports thread awareness such as the in Figure 1, will execute the breakpoint, but then check the thread identifier that is associated with the active thread that reached the breakpoint. If the thread identifier is not for the desired thread, program execution will simply continue.
Similarly, a thread-aware debugger will enable stopping and starting individual threads, colloquially known as freezing and thawing respectively. Freezing a thread enables the developer to minimize potential interference between threads when analyzing an execution flow.
The third issue in multi-core processor debugging is the realization that all local variables and even the cache contents are most likely thread-specific. This observation stresses the need for awareness of the code and its execution context including processor and specific thread. This issue is also true for a heavily multithreaded application executing on a single processor core system, except for the cache line considerations.
Multi-core debugging at system level adds additional complexity, especially below the OS layer focusing on firmware or bootloader debugging.
When debugging OS-independent code on a multi-core system it is important to know which processor cores have set breakpoints. Questions to consider include:
- Will a breakpoint stop execution of all cores or only of one specific core?
- If memory is shared between the processor cores and execution reaches a breakpoint, is there a core context switch?
The debugger on a multi-core system should notify when changes occur in the processor core context. Processor core affinity on a homogeneous multi-core system will typically be implemented the same way as the breakpoint thread affinity discussed in the previous paragraphs. In this case, the breakpoint is reached by all processor cores, but if the core identifier does not match, execution continues.
Considerations for Hyper-Threading Technology
From a debugging perspective there is really no practical difference between a physical processor core and a logical core that has been enabled via Intel Hyper-Threading Technology. Enabling hyper-threading occurs as part of the platform initialization process in your BIOS. Therefore, there is no noticeable difference from the application standpoint between a true physical processor core and an additional logical processor core. Since this technology enables concurrent execution of multiple threads, the debugging challenges are similar to true physical multi-core processors.