This lab is a short demonstration of the Linux environment on the Zynq UltraScale+ MPSoC illustrating how to debug a Linux software application.
In this lab, you will use the Xilinx Software Development Kit (SDK) to run and debug a simple Linux software application project. The target Ultra96 development board will automatically boot Linux from an SD card.
There are five experiments to be completed in this lab exercise:
- Create the SDK Workspace and import the application source code.
- Run the application and examine its behavior. Does it seem like there is a bug?
- Debug the application. Find and fix the software bug.
- Profile the application to examine where in the software is the CPU spending the most time.
- Build an application native on the Ultra96 development board.
When you have completed this lab you will know how to do the following:
- Set up an SDK software application project for debugging
- Use the many features of the SDK debugger
- Connect the 12V power supply to the Ultra96 barrel jack (J5).
- Connect the USB JTAG/UART port of the Ultra96 JTAG/UART adapter to a PC using a MicroUSB cable.
- Insert the supplied USB Ethernet dongle into either USB host port on the Ultra96 board and connect the Ethernet port of the dongle directly to the Ethernet port on the host PC.
- Insert the microSD card into the SD card slot (J4).
Before we get started with the lab experiments, there are a few things we need to do first
- Verify the Ultra96 board is assembled and connected to the host laptop as shown in the Experiment Setup section and that the boot mode switches are set for SD card boot. The silkscreen on the PCB describes these switch settings.
- Turn on the Ultra96 board by pressing the small SW3 power switch near the power input barrel jack. You should see the DS6 (DONE) LED turn green and a short time later the DS8 (WiFi) and DS1 (Bluetooth) LEDs will turn on. Once the board has booted the LED0 LED will blink in a heartbeat pattern.
- Log into the Ubuntu laptop.
User: user
Password: password
- Set the IP address of the Ubuntu laptop to 192.168.11.12. The screenshots below will look slightly different than on the lab laptop.
- Right-click to the
icon on the top Ubuntu toolbar and select Edit Connections…
- Select Wired Connection 1 and click on Edit.
- Click on the IPv4 Settings tab and change the Method to Manual.
- Click on the Add button to set a new IP address.
- Click in the space under Address to set the new IP address as follows. Click Save to and the click Close on the following window to continue.
- Address: 192.168.11.12
- Netmask: 255.255.255.0
- Open a command terminal window by clicking the
icon on the Ubuntu taskbar. Alternatively you may right-click on an empty area of the Ubuntu desktop and select Open Terminal.
- Determine the COM port being used by the USB UART.
$ ls /dev |grep USB
You should see two USB ports identified. The USB0 device is used for JTAG and the USB1 device is the UART.
- Open a PuTTY UART console window in a background shell for the COM port used by the Ultra96 board.
$ putty /dev/ttyUSB1 -serial -sercfg 115200 &
Leave the terminal window open. It will be used again later.
- Go to the PuTTY window and log into the Ultra96 board.
User: root
Password: root
- Set the IP address of the Ultra96 board to 192.168.11.11
# ifconfig eth0 192.168.11.11
- Verify the Ethernet link between the laptop and Ultra96 is active. Do not close the PuTTY window.
# ping 192.168.11.12
The Xilinx SDK uses a ‘workspace’ to store the source files and metadata for the software application we are developing. A workspace may include more than one software application for the same underlying hardware.
General Instruction:Launch Xilinx Software Development Kit (SDK) to create the workspace, create a new Linux application, import the software application source, and build an executable that can be run on the Ultra96 target.
Step-by-Step Instructions:Follow the instructions below to create the workspace, create a new Linux application, import the application source code, and build the executable to run on the Ultra96 board.
- Go the terminal command window and launch Xilinx Software Development Kit (SDK) if not already open. Use the ‘&’ operator to open the Xilinx SDK in the background so we can continue to use this command shell.
$ xsdk &
SDK creates a workspace environment consisting of project files, tool settings, and the software application. Once set, you cannot change the location of this workspace. If it is necessary to move a software application to another location or computer, use the Import and Export facilities built into SDK.
- Click Browse and navigate to the /home/user/xdf_labs/emb_lab1/wrk folder and select Create Folder.
- Name the folder sdk_workspace and press enter, then click OK to continue. Click OK again to launch the Xilinx SDK in the selected folder.
- Click on Create Application Project.
- Set the following options and click Next:
- Project name: matrix_mult
- OS Platform: linux
- Processor Type: psu_cortexa53
- Select the Linux Empty Application template and click Finish:
- Expand the new matrix_mult application in the Project Explorer pane and right-click on the src folder and select Import…
- Expand the General category folder and select File System then click Next.
- Navigate to the /home/user/xdf_labs/emb_lab1/src folder and click OK.
- Select the matrix_multiply.c source file and click Finish. The source will be imported and the app will build.
- Verify the app built successfully by double-clicking on the Console tab. Double-click the tab again to return the console to its normal position.
Create a run configuration to run the application remotely on Ultra96 board over the Ethernet connection. The matrix multiply application performs two loops to perform the matrix multiplications. There is an outer loop of 20 iterations that runs an inner loop of 1024 32x32 matrix multiplies. The outer while() loop evaluates the exit conditions for a button press on the Ultra96 board, <ctrl>-c press on the host PC, or reaching the maximum loop count. After each completed loop of 1024 matrix multiply the user LEDs on the Ultra96 board will rotate in a clockwise pattern. This is a visual indication on the board that the program is running. The outer loop count in the software counts 20 iterations of the inner loop, so each LED should be toggled on/off 5 times.
General Instruction:Use the Xilinx SDK to create a new run configuration and deploy the application code remotely on the target Ultra96 board hardware over an Ethernet connection.
Step-by-Step Instructions:Follow the instructions below to run the application on the Ultra96 board.
- Before we can run the matrix multiply application on the Ultra96 board, we need to first configure the Linux TCF Agent with the Ethernet IP address of the Ultra96 board. Expand the Linux TCF Agent in the Target Connections pane, right-click on Linux Agent [default] and select Edit.
- Recall from
Experiment 0
that we set the IP address of the Ultra96 board to 192.168.11.11. Click in the Host box and change the IP address to this IP address and click OK.
- Right-click on the matrix_mult application in the Project Explorer pane and select Run As Launch on Hardware (System Debugger)
Alternatively you may also expand the Run icon on the toolbar and select Run As Launch on Hardware (System Debugger).
- The app will download to the Ultra96 board and launch automatically. Double-click on the Console tab to see it run. Double-click the tab again to return the console to its normal position.
- As you can probably imagine, the matrix multiply is a CPU-intensive task. We can use the Linux top command to examine just how busy the processing system is running this application. Go to the PuTTY window and run this command.
# top
- Notice that the processing system - all four ARM Cortex-A53 CPU cores - are nearly 100% busy performing the matrix multiplies! This will be interesting to remember for Lab 2 later. Press “q” to stop the top application and return to the Linux command line.
- Also notice that the application never stops. It appears to loop forever - that could be a sign there is a bug in the program. We will check for bugs in
Experiment 3
. Return to the Xilinx SDK and press <ctrl>-c in the console window where the application results are being displayed to stop the matrix multiply application.
Running the program like we did in
Experiment 2
is a good way to test the program and make sure it works as expected, but if there are obscure bugs in the software then you will likely want to use a debugger to examine the code as it runs on the processor. There is an error in the matrix multiply application that we will use the SDK debugger to find and fix. Recall from Experiment 2 that the matrix multiply application performs an outer loop of 20 iterations that runs an inner loop of 1024 32x32 matrix multiplies. There is a main while() loop that evaluates the exit conditions for a button press on the Ultra96 board, <ctrl>-c press on the host PC, or reaching the maximum loop count.General Instruction:Use the Xilinx SDK to debug the application as it is running on the Ultra96 board. Find and fix the error in the source code.
Step-by-Step Instructions:Follow the instructions below to debug the application running on the Ultra96 board.
- We will reuse the Run configuration from
Experiment 2
as our application Debug configuration. Debug configurations simply associate an ELF object file to a target for execution. In this case, the target is a hardware board accessed over a network TCP/IP connection.
In the Project Explorer pane, right-click the matrix_mult application project and select the Debug As Launch on Hardware (System Debugger) menu item.
- The SDK may ask if you want to change to the Debug perspective. Click Yes.
- After the application debug configuration launches, observe that program operation is suspended at the first executable statement in main() (not running).
- Note that local variables for the current function are shown in the Variables tab.
- Use the debugger to verify the switch toggling by using breakpoints and identify how to run and halt a program thread. Begin by selecting the Breakpoints tab. We haven’t set a breakpoint yet, so this window should be blank. If this tab is not open, you may open the tab by selecting the Window Show View Breakpoints menu item.
- The matrix_multiply.c source file should be visible in the sources panel. Click within the source code panel to make it active.
- The editor window panel has a line numbers feature that is turned off by default. To make it easier to locate lines of code referenced in this lab turn on line numbers in the editor panel. In the editor panel, right-click in the gray space to the right of the pane and select the Show Line Numbers option.
- Set a breakpoint to check the loop count incrementing. Locate the line of control code that falls within the conditional statement which checks for the loop count to be less than the maximum loop count on line 405. The line number can also be seen in the lower toolbar of SDK. The first set of digits represents the text line number and the second set of digits represents the text column number.
Double-click on line number 405 within the shaded orange strip on the left of the source editor to set a breakpoint there (a check mark becomes visible). Note that the breakpoint that has just been set now appears in the Breakpoints panel.
- Run the program by clicking the Play/Resume button (green triangle in the top toolbar) to run the program. If you encounter a series of launch errors, simply terminate and relaunch the debug session to recover.
The program will stop at the breakpoint to evaluate the loop conditions. The program suspends execution at line number 405.
- Take some time to scroll through and evaluate each of the variables in the Variables panel. The led_loop_count variable is getting assigned to a value of 0 as would be expected since this is the first time entering this while() loop.
- The led_loop_count variable should increment each time the while() loop is executed. Click on the Step Over button a few times to advance code execution ahead so we enter the while() loop.
- Application execution advances to the next line of code each time the Step Over button is pressed and execution is again suspended. Notice now that the led_loop_count variable has not been updated yet.
- Continue executing the program by clicking the Play/Resume button (green triangle) to resume the program execution again. Notice that the led_loop_count variable has incremented as expected since we just completed an iteration of the while() loop.
- Continue executing the program by clicking the Play/Resume button (green triangle) to resume the program execution again.
Notice the led_loop_count variable has not incremented as expected. This is a clue to the nature of the bug that is being tracked down.
- Manually looking through the source code main control loop for other instances of the led_loop_count variable could take up valuable developer time. Click within the source panel and use the <ctrl>-f keyboard shortcut to open the Find/Replace tool and enter led_loop_count in the Find field. Click the Find button to locate other instances where this variable is used.
- We find that the only other code locations where the led_loop_count variable is accessed is on line 468 where it is initialized to one before returning to the beginning of the main control loop and again on line 405 where it is evaluated as part of the control loop. Here we see something that is likely the cause of the bug that we have observed. Rather than incrementing the variable, the developer made a mistake by omitting the plus sign and inadvertently made this into an assignment statement. This can be a tricky type of bug to track down because the syntax is correct and the code is operational, but the program does not behave correctly. Now that it has been located, let us correct the increment statement and see if that resolves the errant behavior we have observed.
- Stop debugger execution by clicking on the Terminate button in the Debug control panel.
- Edit the source code to change the assignment statement to an increment statement. After saving the changes to the source file, notice that it is automatically rebuilt in the background.
- Re-launch the Debug configuration so that we can verify that the bug has been corrected. In the Debug panel, right-click and select the Relaunch menu item. The debug configuration loads the updated target executable to the target platform and halts execution at the main control routine.
- Use the debugger to verify the led_loop_count incrementing by using breakpoints to evaluate whether the code changes were effective in resolving the bug. Run the program by clicking the Play/Resume button (green triangle) to run the program.
The program again suspends execution at line number 405.
- Continue executing the program by clicking the Play/Resume button (green triangle) to resume the program execution again.
Notice how the led_loop_count variable now increments as it is supposed to. The bug has been resolved by correcting the increment statement as performed in step 18.
- Do not close the debugger. We will continue to use this in
Experiment 4
.
Questions:
Answer the following question:
- Why did the assignment statement prevent the application from operating properly?
___________________________________________________________________
___________________________________________________________________
___________________________________________________________________
Experiment 4: Profile the ApplicationRecall in
Experiment 2
we identified that the matrix multiply application consumes nearly all of the CPU resources when it is running on the Ultra96 board. The Linux ‘top’ utility told us this, but that is actually a bit vague since it doesn’t tell us what part of the running application is consuming so much of the CPU resources. To identify that we can use the SDK TCF Profiler to examine what software application task(s) are using the CPU resources the most.General Instruction:Use the Xilinx SDK profiler to examine the performance of the application as it is running on the Ultra96 board.
Step-by-Step Instructions:Follow the instructions below to run the profiler on the application running on the Ultra96 board.
- With the debugger still running from
Experiment 3
, launch the TCF Profiler view by navigating the SDK menu bar to Window Show View Other.
- In the menu that opens select Debug TCF Profiler and click OK.
- Before we launch the profiler we need to change the rate at which it samples the running software. Click on the Start icon in the TCF Profiler pane.
- Change the View update interval (msec) to 10 and click OK.
- Run the program by clicking the Play/Resume button (green triangle) to resume the program execution again.
- Navigate to where we set the breakpoint in the matrix_multiply.c file in the source editor and remove the breakpoint by double-clicking on line 405.
- Run the program by clicking the Play/Resume button (green triangle) to resume the program execution again.
- Examine the TCF Profiler results and notice that nearly all - over 90% - of the program execution time is being spent in the mmult_sw function.
- The TCF Profiler will stop when the application stops (when the led_loop_count reaches max_loop_count). This takes about 45 seconds. You may stop
and disconnect
the debugger from the running system and exit the SDK.
It is clear this software application is very CPU-intensive, and we haven’t even examined just how fast the software is able to complete the matrix multiply. If we had identified a multiply performance requirement, could this software have achieved it? Given that we are running Linux on the Ultra96 board that it has its own set of CPU requirements for subsystems like the X windowing manager, TCP/IP stack, USB stack, etc., running a software application that is so CPU intensive can easily cause problems if Linux is not able to keep them serviced because it is too busy doing matrix multiplies. Since we are using a Zynq UltraScale+ device with an abundance of FPGA logic resources, and FPGAs are known to be good at math functions (right?), there must be a way to offload this intensive multiply task from the CPU and accelerate it in the programmable logic. Stay tuned for Lab 2 to learn how to do just that using the Xilinx SDSoC tool.
Experiment 5: Build an Application on the Ultra96 TargetThe Xilinx SDK is a great IDE for developing Linux software applications, but what if you are given a package of software sources you just want to build and run on the target? Perhaps a software utility that is downloaded directly to the Ultra96 board and we just want to build and install it. In this experiment we use the gcc toolchain that is installed on the Ultra96 to natively build and run a simple software application.
General Instruction:Copy the helloworld.c source file from the laptop to the Ultra96 board and use gcc on the Ultra96 to build it. Run the new application on the Ultra96 board.
Step-by-Step Instructions:Follow the instructions below to build and run a simple application on the Ultra96 board.
- Go to the terminal command window that was opened earlier and navigate to the following folder. If you need to open a new terminal go back to
Experiment 0
and rerun the steps there.
$ cd /home/user/sdf_labs/emb_lab1/src
- Use the Linux secure copy (scp) command to copy the file from the Ubuntu Linux host to the Ultra96 board. Answer yes when prompted to store the ssh key for this connection.
$ scp./helloworld.c root@192.168.11.11:/mnt/.Password: root
- Go to the PuTTY window and navigate to the folder where the application source file was just copied. If you need to open a new PuTTY window go back to
Experiment 0
and rerun the steps there.
# cd /mnt
- Run the gcc compiler on the new application source file and build the executable.
# gcc./helloworld.c -o helloworld
- Run the new application.
#./helloworld
- The popular Linux vi and vim editors are also installed on the Ultra96 board, so feel free to edit the helloworld.c file to create your own message or add other features to the application. Rebuild and rerun the application as necessary.
- When finished please shutdown the Ultra96 board. DO NOT unplug the board without doing a proper shutdown or else the filesystem may become corrupted. Press and hold the SW3 power switch once you see the power down message. The board will power off after about 10 seconds.
# shutdown -h now
- Close the Xilinx SDK, terminal, and PuTTY windows.
Comments