From 8db468ffde833523535720e8ec8119d760a9561a Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Fri, 17 Aug 2007 01:07:10 +0000 Subject: 2007-08-17 Chris Johns * Makefile.am, README, configure.ac, capture/.cvsignore, capture/Makefile.am, capture/capture.doc, capture/capture.scn, capture/init.c, capture/system.h, capture/test1.c: Add a sample test for the capture engine. --- testsuites/samples/ChangeLog | 7 + testsuites/samples/Makefile.am | 2 +- testsuites/samples/README | 11 + testsuites/samples/capture/.cvsignore | 2 + testsuites/samples/capture/Makefile.am | 26 ++ testsuites/samples/capture/capture.doc | 508 +++++++++++++++++++++++++++++++++ testsuites/samples/capture/capture.scn | 137 +++++++++ testsuites/samples/capture/init.c | 73 +++++ testsuites/samples/capture/system.h | 92 ++++++ testsuites/samples/capture/test1.c | 270 ++++++++++++++++++ testsuites/samples/configure.ac | 1 + 11 files changed, 1128 insertions(+), 1 deletion(-) create mode 100644 testsuites/samples/capture/.cvsignore create mode 100644 testsuites/samples/capture/Makefile.am create mode 100644 testsuites/samples/capture/capture.doc create mode 100644 testsuites/samples/capture/capture.scn create mode 100644 testsuites/samples/capture/init.c create mode 100644 testsuites/samples/capture/system.h create mode 100644 testsuites/samples/capture/test1.c (limited to 'testsuites') diff --git a/testsuites/samples/ChangeLog b/testsuites/samples/ChangeLog index 7542d0cd96..8d8d29c68c 100644 --- a/testsuites/samples/ChangeLog +++ b/testsuites/samples/ChangeLog @@ -1,3 +1,10 @@ +2007-08-17 Chris Johns + + * Makefile.am, README, configure.ac, capture/.cvsignore, + capture/Makefile.am, capture/capture.doc, capture/capture.scn, + capture/init.c, capture/system.h, capture/test1.c: Add a sample + test for the capture engine. + 2007-07-24 Joel Sherrill * nsecs/init.c: Add include of unistd.h for sleep() prototype. diff --git a/testsuites/samples/Makefile.am b/testsuites/samples/Makefile.am index b2afb0e8d5..82560d18ff 100644 --- a/testsuites/samples/Makefile.am +++ b/testsuites/samples/Makefile.am @@ -4,7 +4,7 @@ ACLOCAL_AMFLAGS = -I ../aclocal -SUBDIRS = hello ticker base_sp unlimited minimum fileio +SUBDIRS = hello capture ticker base_sp unlimited minimum fileio if MPTESTS ## base_mp is a sample multiprocessing test diff --git a/testsuites/samples/README b/testsuites/samples/README index b6e03a41f5..03234e95d7 100644 --- a/testsuites/samples/README +++ b/testsuites/samples/README @@ -42,6 +42,12 @@ The following describes each of the sample applications: This is intended as a starting point for custom developed single processor applications. + capture + + This simple application starts the monitor and allows you access + to the capture engine. The capture engine provides a trace of + RTEMS activity and is used to debug your application. + cdtest A very simple C++ application which demonstrates that it is @@ -70,3 +76,8 @@ The following describes each of the sample applications: This test has an initialization task create three application tasks which sleep and periodically wake up and print the time. + unlimited + + This is a test for the umlimited object feature of RTEMS. Here + you can configure RTEMS to give as many objects as memory + in the Workspace. diff --git a/testsuites/samples/capture/.cvsignore b/testsuites/samples/capture/.cvsignore new file mode 100644 index 0000000000..282522db03 --- /dev/null +++ b/testsuites/samples/capture/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/testsuites/samples/capture/Makefile.am b/testsuites/samples/capture/Makefile.am new file mode 100644 index 0000000000..6a22fbafa2 --- /dev/null +++ b/testsuites/samples/capture/Makefile.am @@ -0,0 +1,26 @@ +## +## $Id$ +## + +MANAGERS = io event + +rtems_tests_PROGRAMS = capture.exe +capture_exe_SOURCES = init.c test1.c system.h + +dist_rtems_tests_DATA = capture.scn +dist_rtems_tests_DATA += capture.doc + +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg +include $(top_srcdir)/../automake/compile.am +include $(top_srcdir)/../automake/leaf.am + +unlimited_exe_LDADD = $(MANAGERS_NOT_WANTED:%=$(PROJECT_LIB)/no-%.rel) + +LINK_OBJS = $(capture_exe_OBJECTS) $(capture_exe_LDADD) +LINK_LIBS = $(capture_exe_LDLIBS) + +capture.exe$(EXEEXT): $(capture_exe_OBJECTS) $(capture_exe_DEPENDENCIES) + @rm -f capture.exe$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/samples/capture/capture.doc b/testsuites/samples/capture/capture.doc new file mode 100644 index 0000000000..5333dc643c --- /dev/null +++ b/testsuites/samples/capture/capture.doc @@ -0,0 +1,508 @@ +# +# $Id$ +# +# COPYRIGHT (c) 1989-1999. +# On-Line Applications Research Corporation (OAR). +# +# The license and distribution terms for this file may be +# found in the file LICENSE in this distribution or at +# http://www.rtems.com/license/LICENSE. +# + +Capture Engine Tutorial + +The Capture Engine is a software trace tool built into the RTEMS operating +system. Being software it does use CPU and memory resources. If do not use it +does not effect RTEMS or your application. The Capture Engine is designed to +placed the lowest load possible on the system when operating and when disabled +does not effect RTEMS. It binds to RTEMS at runtime and does not require RTEMS +or your application to be rebuilt inorder to use it. + +This tutorial will guide you through the building of RTEMS and the sample +programs for the pc586 BSP on Windows using the MinGW tools. The RTEMS Capture +Engine sample programmes are found in CVS and will be available in the next +release of RTEMS. The turoial will show how to create filters and triggers and +how to obtain a trace of the tasks running. The Capture Engine Command Line +Interface (CLI) will be used as this currently is the only available interface +to the Capture Engine. + +The tutorial uses the PC586 BSP running under QEMU. This provides a stable +environment that be easly duplicated on readly available hardware. If you are +new to RTEMS, simulators helps you get RTEMS running quickly. The RTEMS Wiki +provides the information needed to download and install these tools. + +In this tutorial I have placed the RTEMS source code into the Windows +directory: + + c:\rtems\src\rtems-4.7.0 + +RTEMS is configured using the shell MSYS with this command: + + $ /c/rtems/src + $ mkdir pc586 + $ cd pc586 + $ /c/rtems/src/rtems-4.7.0/configure --target=i386-rtems4.8 \ + --enable-network --enable-posix --enable-itron \ + --enable-tests=samples --enable-maintainer-mode \ + --enable-cxx --enable-rtems-bsp=pc586 + $ make all + +If you wish to use the Windows Command prompt open an RTEMS Command prompt +window by running the c:\rtems\i386\rtems-cmd.bat batch file from Explorer. The +shell commands become: + + RTEMS(i386) C:\rtems\i386> cd ..\src + RTEMS(i386) C:\rtems\src> mkdir pc586 + RTEMS(i386) C:\rtems\src> cd pc586 + RTEMS(i386) C:\rtems\src\pc586> sh /c/rtems/src/rtems-4.7.0/configure + --target=i386-rtems4.7 --enable-network --enable-posix --enable-itron + --enable-tests=samples --enable-maintainer-mode --enable-cxx + --enable-rtems-bsp=pc586 + RTEMS(i386) C:\rtems\src\pc586> make all + +Install the Windows version of QEMU and run with the following command: + + RTEMS(i386) C:\rtems\src\pc586> type c:\rtems\i386\bin\qemu.bat + rem @echo off + set QEMU=C:\rtems\i386\qemu-0.8.2-windows + %QEMU%\qemu -L %QEMU% -m 128 -boot a -fda c:\rtems\i386\rtems-boot.img + -hda fat:%1 %2 %3 + +You will need to download the GRUB boot loader image from the RTEMS +website. This image will boot the QEMU PC and attempt to read a GRUB +configuration file from the hda root directory. You pass the qemu.bat file the +path on your disk to the hda root directory. The capture engine examples are in +the standard testsuite examples directory. For our Windows host once built they +are in: + + rtems\src\pc586\i386-rtems4.8\c\pc586\testsuites\samples + +In this directory create a GRUB configuration file with an entry similar to +this one: + + RTEMS(i386) C:\rtems\src\pc586> type i386-rtems4.8\c\pc586\testsuites\sam + ples\rtems-grub.cfg + # RTEMS Grub configuration for the Samples + set default=0 + + menuentry "RTEMS - Capture" { + set root=(hd0,0) + multiboot (hd0,0)/capture/capture.exe + } + +It has a single entry the Capture Engine test. Change to the samples directory +and run QEMU using the QEMU batch file we created above: + + RTEMS(i386) C:\rtems\src\pc586> cd i386-rtems4.7\c\pc586\testsuites\samples + RTEMS(i386) C:\rtems\src\pc586\i386-rtems4.7\c\pc586\testsuites\samples> qemu . + +A QEMU console will open and you will see the GNU GRUB menu. The "RTEM - +Capture" menu item will be highlighted. Press Enter and GRUB will load and +execute the RTEMS Capture Engine example. + +RTEMS will only take a moment to initialise and you will be presented with the +RTEMS monitor login prompt: + + Initialized console on port CONSOLE + + + *** CAPTURE ENGING TEST *** + + Monitor ready, press enter to login. + + rtems $ + +The standard configuration is the Capture Engine not initialised and not +running. It needs to be initialised. You enter a trace buffer size in bytes +with the open command: + + rtems $ copen 5000 + capture engine open + rtems $ + +If you look in the Capture Engine example source code 'test1.c' a CLI command +'test1' is added to the RTEMS monitor. When you enter the 'test1' command the +'RMON' task will call 'capture_test_1()'. This function creates a task called +'CT1a' and starts it, then task 'CT1b' is created and started and finally +'CT1c' is created and started. All tasks are passed the object id of a +semaphore as a task argument. The RMON command thread then loops sleeping for 1 +second, waking to check if all of the tasks that have been created have been +deleted themselves. Once all tasks have been deleted the command returns +presenting the prompt to the user. + +The first task started is 'CT1a'. It obtains the mutex, waits 2.5 seconds, +releases it then deletes itself. The second task 'CT1b' loops until task 'CT1c' +has been deleted. The last task 'CT1c' also obtains the semaphore, waits 0.5 +seconds, releases the semaphore then deletes itself. + +The priority of RMON is 1 and is the highest priority task. The task 'CT1a' has +the lowest priority of 102, task 'CT1b' has a priority of 101, and 'CT1c' is the +highest priority of the three created tasks with 100. + +The test generates priority inheritance where task 'CT1a' inherits the priority +of task 'CT1c' and the Capture Engine captures this for you to observe. Task +'CT1a' obtains the semaphore with a priority of 102 then sleeps. Task 'CT1b' +consumes all of the CPU time with a priority of 101. Normally task 'CT1a' would +never run again. Task 'CT1c' runs and blocks waiting for the semaphore. When +task 'CT1a' wakes after 2.5 seconds it inherits the priority of task 'CT1c' +which is 100, higher than task 'CT1b'. Task 'CT1a' can now run and releases the +semaphore which task 'CT1c' obtains. After it wakes from a 0.5 second sleep it +releases the semaphore and deletes itself which causes task 'CT1b' to delete +itself. + +We could just open the capture engine, enable it and start tracing how-ever +there could be a large number of context switches before we get to our test and +the tasks events we are interested in. This would create a large amount of +trace noise and add extra load onto the system capturing this noise. A software +capture tool like this one is effective if we can filter the events recorded +into the trace buffer and if we can control when we trigger to start +recording. + +The simplest type of filter is the ceiling and floor priority filter. Here we +narrow the range of priorities captured. This is useful for applications which +typically have a middle range of priorites removing device type tasks such as +networking tasks or file system tasks as well as low priority back ground +tasks. Our test tasks have a priority range of 100 to 102. The filter is set +with the following commands: + + rtems $ cwceil 100 + watch ceiling 100. + rtems $ cwfloor 102 + watch floor is 102. + rtems $ + +We also need to enable the global watch. This causes all tasks in the priority +range to be captured: + + rtems $ cwglob on + global watch enabled. + rtems $ + +You can set or clear a trigger. To start with we will use the simplest trigger +we can have. This is just a task name. As the RMON task handles the RTEMS +monitor keyboard and executes the commands we shall trigger when this task +effects a task in our priority range. To set the trigger use this command: + + rtems $ ctset RMON + trigger set. + rtems $ cwlist + watch priority ceiling is 100 + watch priority floor is 102 + global watch is enabled + total 1 + 00000000 RMON g- T:S------ F:----- + rtems $ + +The 'cwlist' command lists the watch and trigger configuration. You will see +the RMON trigger line has a number, a label and flags. Later you will be given +more detail on these values. The number is an RTEMS object id. It is 0 which +means use the label when looking for the trigger. We could have entered the +task id for RMON in the trigger rather than the label. + +The capture engine is disabled after being opened and needs to be enabled. The +ability to enable and disable the capture engine with a single command allows +you to remove any effect the capture may have on the application while you are +tracing a problem. To enable enter: + + rtems $ cenable + capture engine enabled. + rtems $ + +To dump a recorded the trace you enter: + + rtems $ ctrace + rtems $ + +The trace buffer is empty. Notice how the capture engine is not triggering on +the RMON task or the execution of any other tasks that may be in the +system. Every monitor key press causes the RMON task to be switched in to +run. It is now time to run the test so enter the 'test1' command: + + rtems $ test1 + rtems $ + +After a few seconds the RTEMS monitor prompt will return and we can dump the +trace. + + rtems $ ctrace + 91.980000 0a010002 RMON 1 1 CREATED_BY + 91.980000 0a010003 CT1a 102 102 CREATED + 91.980000 0a010002 RMON 1 1 STARTED_BY + 91.980000 0a010003 CT1a 102 102 STARTED + 91.980000 0a010003 CT1a 102 102 SWITCHED_IN + 91.980000 0a010003 CT1a 102 102 BEGIN + 91.980000 0a010003 CT1a 102 102 SWITCHED_OUT + 92.980000 0a010002 RMON 1 1 CREATED_BY + 92.980000 0a010004 CT1b 101 101 CREATED + 92.980000 0a010002 RMON 1 1 STARTED_BY + 92.980000 0a010004 CT1b 101 101 STARTED + 92.980000 0a010004 CT1b 101 101 SWITCHED_IN + 92.980000 0a010004 CT1b 101 101 BEGIN + 93.980000 0a010004 CT1b 101 101 SWITCHED_OUT + 93.980000 0a010002 RMON 1 1 CREATED_BY + 93.980000 0a010004 CT1c 100 100 CREATED + 93.980000 0a010002 RMON 1 1 STARTED_BY + 93.980000 0a010005 CT1c 100 100 STARTED + 93.980000 0a010005 CT1c 100 100 SWITCHED_IN + 93.980000 0a010005 CT1c 100 100 BEGIN + 93.980000 0a010005 CT1c 100 100 SWITCHED_OUT + 93.980000 0a010004 CT1b 101 101 SWITCHED_IN + rtems $ + +The trace dump command by default displays 24 trace records. We have more so +enter the trace command until all have been displayed. The details of the trace +data will be discussed once we have all the trace data. + + rtems $ ctrace + 94.480000 0a010004 CT1b 101 101 SWITCHED_OUT + 94.480000 0a010003 CT1a 102 100 SWITCHED_IN + 94.480000 0a010003 CT1a 102 102 SWITCHED_OUT + 94.480000 0a010005 CT1c 100 100 SWITCHED_IN + 94.480000 0a010005 CT1c 100 100 SWITCHED_OUT + 94.480000 0a010004 CT1b 101 101 SWITCHED_IN + 94.980000 0a010004 CT1b 101 101 SWITCHED_OUT + 94.980000 0a010005 CT1c 100 100 SWITCHED_IN + 94.980000 0a010005 CT1c 100 100 DETELED_BY + 94.980000 0a010005 CT1c 100 100 DETELED + 94.980000 0a010004 CT1b 101 101 SWITCHED_IN + 94.980000 0a010004 CT1b 101 101 DELETED_BY + 94.980000 0a010004 CT1b 101 101 DELETED + 94.980000 0a010003 CT1a 102 100 SWITCHED_IN + 94.980000 0a010003 CT1a 102 100 DELETED_BY + 94.980000 0a010003 CT1a 102 100 DELETED + rtems $ + +The first column of the trace data is the time stamp. The test command started +when the time stamp was 91.98 seconds and took 3 seconds to run. Your trace +will have a different starting value but the total time should be 3 +seconds. The actual start value is the time it takes you to enter the various +capture commands. It would seem I am rather slow. + +The second column is the object id. In this case they are task ids. The third +column is the object name. + +The fourth is the real task priority and fifth column is the executing task +priority. The executing priority follows any priority inheritance. The last +column is the event the capture engine has captured. + +The first couple of records: + + 91.980000 0a010002 RMON 1 1 CREATED_BY + 91.980000 0a010003 CT1a 102 102 CREATED + +show at 91.98 seconds task id '0a010002' named 'RMON' with a priority of 1 and +executing at a priority of 1 created task id '0a010003' named 'CT1a' with a +priority of 102 and an executing priority of 102. Next 'RMON' started 'CT1a' +and it was switch into context, began running, then was switched out. + + 91.980000 0a010002 RMON 1 1 STARTED_BY + 91.980000 0a010003 CT1a 102 102 STARTED + 91.980000 0a010003 CT1a 102 102 SWITCHED_IN + 91.980000 0a010003 CT1a 102 102 BEGIN + 91.980000 0a010003 CT1a 102 102 SWITCHED_OUT + +The task 'CT1a' was switched out because it blocked on the semaphore. + +If you look at the 'test1' command's code you will see the command sleeps for 1 +second after starting the task. This is why the lower priority task 'CT1a' is +switched in and able to run. The sleep can be seen in the next event where +'RMON' creates 'CT1b'. The timestamp is 1 second later. + + 92.980000 0a010002 RMON 1 1 CREATED_BY + 92.980000 0a010004 CT1b 101 101 CREATED + 92.980000 0a010002 RMON 1 1 STARTED_BY + 92.980000 0a010004 CT1b 101 101 STARTED + 92.980000 0a010004 CT1b 101 101 SWITCHED_IN + 92.980000 0a010004 CT1b 101 101 BEGIN + 93.980000 0a010004 CT1b 101 101 SWITCHED_OUT + +There are no 'RMON' switched in or switched out events. These are being +filtered by the priority range filter. We see the 'RMON' CREATED_BY events as +these are actually occuring on test tasks which are in the priority range. + +The create and start process is repeated for the remaining two tasks. The +following section of the trace show 'CT1c' being switch out and 'CT1b' being +switch in. Task 'CT1b' loops consuming all of the CPU time until 'CT1a' +wakes. This is 500 milli-seconds. + + 93.980000 0a010005 CT1c 100 100 BEGIN + 93.980000 0a010005 CT1c 100 100 SWITCHED_OUT + 93.980000 0a010004 CT1b 101 101 SWITCHED_IN + 94.480000 0a010004 CT1b 101 101 SWITCHED_OUT + 94.480000 0a010003 CT1a 102 100 SWITCHED_IN + +When 'CT1a' wakes it is executing at the priority of 'CT1c' of 100 and so +higher than 'CT1b'. Task 'CT1a' then releases the semaphore dropping it +priority back to 102 allowing 'CT1c' to run. + + 94.480000 0a010003 CT1a 102 102 SWITCHED_OUT + 94.480000 0a010005 CT1c 100 100 SWITCHED_IN + 94.480000 0a010005 CT1c 100 100 SWITCHED_OUT + 94.480000 0a010004 CT1b 101 101 SWITCHED_IN + 94.980000 0a010004 CT1b 101 101 SWITCHED_OUT + 94.980000 0a010005 CT1c 100 100 SWITCHED_IN + +Task 'CT1c' release the semaphore and deletes itself. Task 'CT1b' is switched +in and it is looping waiting for 'CT1c' to delete. This has happen so 'CT1b' +deletes itself. Finally 'CT1a' deletes itself. + + 94.980000 0a010005 CT1c 100 100 DETELED_BY + 94.980000 0a010005 CT1c 100 100 DETELED + 94.980000 0a010004 CT1b 101 101 SWITCHED_IN + 94.980000 0a010004 CT1b 101 101 DELETED_BY + 94.980000 0a010004 CT1b 101 101 DELETED + 94.980000 0a010003 CT1a 102 100 SWITCHED_IN + 94.980000 0a010003 CT1a 102 100 DELETED_BY + 94.980000 0a010003 CT1a 102 100 DELETED + +The delete event shows the task deleting itself as the DELETED_BY event is the +same as the DELETED event. + +We will now explore some more complex filters and triggers. First close the +QEMU window and start QEMU again and open and enable the capture engine: + + rtems $ copen 5000 + capture engine open + rtems $ cenable + capture engine enabled. + rtems $ + +In this example we only want to monitor task 'CT1c' and wish to trigger on a +context switch from 'CT1c' to 'CT1a'. This happens when 'CT1a' releases the +semaphore and CT1c claims it. The set up is: + + rtems $ cwadd CT1c + watch added. + rtems $ cwctl CT1c on + watch enabled. + rtems $ ctset switch CT1c from CT1a + trigger set. + rtems $ cwlist + watch priority ceiling is 0 + watch priority floor is 0 + global watch is disabled + total 1 + 00000000 CT1c -w T:------- F:----- + 0:CT1a/00000000:S---- + rtems $ + +We run the test and capture the output: + + rtems $ test1 + rtems $ ctrace + 61.150000 0a010005 CT1c 100 100 SWITCHED_IN + 61.150000 0a010005 CT1c 100 100 SWITCHED_OUT + 61.650000 0a010005 CT1c 100 100 SWITCHED_IN + 61.650000 0a010005 CT1c 100 100 DELETED_BY + 61.650000 0a010005 CT1c 100 100 DELETED + rtems $ + +The trace shows CT1c being switched in once it has the semaphore then switching +out while it waits 500 milli-seconds, waking and being switched in to delete +itself. The filtering means we can focus on the specific events which we are +interested in and the trigger means we only trace once the specific event we +are interested in occurs. + +The filter and trigger do not need to relate. Lets run a variation of the last +configuation where we watch 'CT1b' and trigger on 'CT1c' being switched to from +'CT1a'. Close the QEMU window and start QEMU again and open and enable the +capture engine: + + rtems $ copen 5000 + capture engine open + rtems $ cenable + capture engine enabled. + rtems $ cwadd CT1b + watch added. + rtems $ cwctl CT1b on + watch enabled. + rtems $ ctset switch CT1c from CT1a + trigger set. + rtems $ cwlist + watch priority ceiling is 0 + watch priority floor is 0 + global watch is disabled + total 2 + 00000000 CT1c -- T:------- F:----- + 0:CT1a/00000000:S---- + 00000000 CT1b -w T:------- F:----- + rtems $ + +You can see 2 watch controls exist, one for the trigger and one for the filter. +Before we run the test we will take a look at the task list using the 'ctlist'. + + rtems $ ctlist + total 2 + 09010001 IDLE 255 255 255 READY a--- 0% 0% (10682) + 0a010002 RMON 1 1 1 READY a--- 0% 0% (826) + rtems $ + +You can see the 2 tasks that are active. These tasks existed before the capture +engine started. The capture engine learns about tasks that exist in a system if +they do something. If a task exists and does nothing the capture engine will +not know about it. Lets run the test then list the tasks again: + + rtems $ test1 + rtems $ ctlist + total 3 + 0a010004 CT1b 101 0 0 READY dtw- 100% 0% (200) + 09010001 IDLE 255 255 255 READY a--- 0% 0% (10682) + 0a010002 RMON 1 1 1 READY a--- 0% 0% (826) + rtems $ + +This time the task lists the test task we are watching 'CT1b'. If how-ever has +been deleted and the task list shows this with the 'd' in the flags. The active +tasks have an 'a'. The capture engine has to retain information on tasks that +have been deleted so the trace data can be generated. The trace buffer holds a +reference to the task's details not the specific details. Once the trace data +has been viewed the task data is no longer needed and released. + + rtems $ ctrace + 551.630000 0a010004 CT1b 101 101 SWITCHED_IN + 552.130000 0a010004 CT1b 101 101 SWITCHED_OUT + 552.130000 0a010004 CT1b 101 101 SWITCHED_IN + 552.130000 0a010004 CT1b 101 101 DELETED_BY + 552.130000 0a010004 CT1b 101 101 DELETED + rtems $ ctlist + total 2 + 09010001 IDLE 255 255 255 READY a--- 0% 0% (10682) + 0a010002 RMON 1 1 1 READY a--- 0% 0% (826) + rtems $ + +Listing the tasks shows 'CT1b' has gone. The trace buffer does not reference +it any more. + +We have now seen the following capture commands: + + copen + cenable + ctlist + cwceil + cwfloor + cwglob + cwadd + cwctl + ctset + ctrace + +The ctset is worth a closer look. The general form of the command is: + + ctset [-?] type [to name/id] [from] [from name/id] + +The 'type' is the type of trigger. The following possible types of triggers +exist: + + switch - a context switch from one task to another task + create - the executing task creates a task + start - the executing task starts a task + restart - the executing task restarts a task + delete - the executing task deletes a task + begin - a task is beginning + exitted - a task is exitting + +With the ctset command you set a trigger for a task. If you do not supply a +from task the type of event can be from any task. You can be more specific by +stating the event for a task must be by a specific task. Looking at the examples +from before we set a trigger on a context switch from CT1a to CT1c with: + + ctset switch CT1c from CT1a diff --git a/testsuites/samples/capture/capture.scn b/testsuites/samples/capture/capture.scn new file mode 100644 index 0000000000..57e045e1a9 --- /dev/null +++ b/testsuites/samples/capture/capture.scn @@ -0,0 +1,137 @@ +*** CAPTURE ENGING TEST *** + +Monitor ready, press enter to login. + +rtems $ +rtems $ copen 5000 +capture engine open +rtems $ cwceil 100 +watch ceiling 100. +rtems $ cwfloor 102 +watch floor is 102. +rtems $ cwglob on +global watch enabled. +rtems $ ctset RMON +trigger set. +rtems $ cwlist +watch priority ceiling is 100 +watch priority floor is 102 +global watch is enabled +total 1 + 00000000 RMON g- T:S------ F:----- +rtems $ cenable +capture engine enabled. +rtems $ ctrace +rtems $ test1 +rtems $ ctrace + 91.980000 0a010002 RMON 1 1 CREATED_BY + 91.980000 0a010003 CT1a 102 102 CREATED + 91.980000 0a010002 RMON 1 1 STARTED_BY + 91.980000 0a010003 CT1a 102 102 STARTED + 91.980000 0a010003 CT1a 102 102 SWITCHED_IN + 91.980000 0a010003 CT1a 102 102 BEGIN + 91.980000 0a010003 CT1a 102 102 SWITCHED_OUT + 92.980000 0a010002 RMON 1 1 CREATED_BY + 92.980000 0a010004 CT1b 101 101 CREATED + 92.980000 0a010002 RMON 1 1 STARTED_BY + 92.980000 0a010004 CT1b 101 101 STARTED + 92.980000 0a010004 CT1b 101 101 SWITCHED_IN + 92.980000 0a010004 CT1b 101 101 BEGIN + 93.980000 0a010004 CT1b 101 101 SWITCHED_OUT + 93.980000 0a010002 RMON 1 1 CREATED_BY + 93.980000 0a010004 CT1c 100 100 CREATED + 93.980000 0a010002 RMON 1 1 STARTED_BY + 93.980000 0a010005 CT1c 100 100 STARTED + 93.980000 0a010005 CT1c 100 100 SWITCHED_IN + 93.980000 0a010005 CT1c 100 100 BEGIN + 93.980000 0a010005 CT1c 100 100 SWITCHED_OUT + 93.980000 0a010004 CT1b 101 101 SWITCHED_IN +rtems $ ctrace + 94.480000 0a010004 CT1b 101 101 SWITCHED_OUT + 94.480000 0a010003 CT1a 102 100 SWITCHED_IN + 94.480000 0a010003 CT1a 102 102 SWITCHED_OUT + 94.480000 0a010005 CT1c 100 100 SWITCHED_IN + 94.480000 0a010005 CT1c 100 100 SWITCHED_OUT + 94.480000 0a010004 CT1b 101 101 SWITCHED_IN + 94.980000 0a010004 CT1b 101 101 SWITCHED_OUT + 94.980000 0a010005 CT1c 100 100 SWITCHED_IN + 94.980000 0a010005 CT1c 100 100 DETELED_BY + 94.980000 0a010005 CT1c 100 100 DETELED + 94.980000 0a010004 CT1b 101 101 SWITCHED_IN + 94.980000 0a010004 CT1b 101 101 DELETED_BY + 94.980000 0a010004 CT1b 101 101 DELETED + 94.980000 0a010003 CT1a 102 100 SWITCHED_IN + 94.980000 0a010003 CT1a 102 100 DELETED_BY + 94.980000 0a010003 CT1a 102 100 DELETED + +*** CAPTURE ENGING TEST *** + +Monitor ready, press enter to login. + +rtems $ copen 5000 +capture engine open +rtems $ cenable +capture engine enabled. +rtems $ cwadd CT1c +watch added. +rtems $ cwctl CT1c on +watch enabled. +rtems $ ctset switch CT1c from CT1a +trigger set. +rtems $ cwlist +watch priority ceiling is 0 +watch priority floor is 0 +global watch is disabled +total 1 + 00000000 CT1c -w T:------- F:----- + 0:CT1a/00000000:S---- +rtems $ test1 +rtems $ ctrace + 61.150000 0a010005 CT1c 100 100 SWITCHED_IN + 61.150000 0a010005 CT1c 100 100 SWITCHED_OUT + 61.650000 0a010005 CT1c 100 100 SWITCHED_IN + 61.650000 0a010005 CT1c 100 100 DELETED_BY + 61.650000 0a010005 CT1c 100 100 DELETED + +*** CAPTURE ENGING TEST *** + +Monitor ready, press enter to login. + +rtems $ copen 5000 +capture engine open +rtems $ cenable +capture engine enabled. +rtems $ cwadd CT1b +watch added. +rtems $ cwctl CT1b on +watch enabled. +rtems $ ctset switch CT1c from CT1a +trigger set. +rtems $ cwlist +watch priority ceiling is 0 +watch priority floor is 0 +global watch is disabled +total 2 + 00000000 CT1c -- T:------- F:----- + 0:CT1a/00000000:S---- + 00000000 CT1b -w T:------- F:----- +rtems $ ctlist +total 2 + 09010001 IDLE 255 255 255 READY a--- 0% 0% (10682) + 0a010002 RMON 1 1 1 READY a--- 0% 0% (826) +rtems $ test1 +rtems $ ctlist +total 3 + 0a010004 CT1b 101 0 0 READY dtw- 100% 0% (200) + 09010001 IDLE 255 255 255 READY a--- 0% 0% (10682) + 0a010002 RMON 1 1 1 READY a--- 0% 0% (826) +rtems $ ctrace + 551.630000 0a010004 CT1b 101 101 SWITCHED_IN + 552.130000 0a010004 CT1b 101 101 SWITCHED_OUT + 552.130000 0a010004 CT1b 101 101 SWITCHED_IN + 552.130000 0a010004 CT1b 101 101 DELETED_BY + 552.130000 0a010004 CT1b 101 101 DELETED +rtems $ ctlist +total 2 + 09010001 IDLE 255 255 255 READY a--- 0% 0% (10682) + 0a010002 RMON 1 1 1 READY a--- 0% 0% (826) diff --git a/testsuites/samples/capture/init.c b/testsuites/samples/capture/init.c new file mode 100644 index 0000000000..891d342b46 --- /dev/null +++ b/testsuites/samples/capture/init.c @@ -0,0 +1,73 @@ +/* Init + * + * This routine is the initialization task for this test program. + * It is called from init_exec and has the responsibility for creating + * and starting the tasks that make up the test. If the time of day + * clock is required for the test, it should also be set to a known + * value by this function. + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * COPYRIGHT (c) 1989-1997. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may in + * the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#define CONFIGURE_INIT + +#include "system.h" +#include +#include + +#include +#include +#include + +void setup_tasks_to_watch (); + +volatile int can_proceed = 1; + +rtems_task Init( + rtems_task_argument ignored +) +{ + rtems_task_priority old_priority; + rtems_mode old_mode; + rtems_event_set out; + + /* lower the task priority to allow created tasks to execute */ + + rtems_task_set_priority(RTEMS_SELF, 20, &old_priority); + rtems_task_mode(RTEMS_PREEMPT, RTEMS_PREEMPT_MASK, &old_mode); + + printf( "\n*** CAPTURE ENGINE TEST ***\n" ); + + while (!can_proceed) + { + printf ("Sleeping\n"); + usleep (1000000); + } + + rtems_monitor_init (0); + rtems_capture_cli_init (0); + + setup_tasks_to_watch (); + + rtems_task_delete (RTEMS_SELF); + + printf( "\nblocking main\n" ); + + rtems_event_receive (RTEMS_EVENT_1, RTEMS_WAIT | RTEMS_EVENT_ANY, + 0, &out); + + printf( "\n*** END OF UNLIMITED TASK TEST ***\n" ); + exit( 0 ); +} + diff --git a/testsuites/samples/capture/system.h b/testsuites/samples/capture/system.h new file mode 100644 index 0000000000..d4d6b6dce5 --- /dev/null +++ b/testsuites/samples/capture/system.h @@ -0,0 +1,92 @@ +/* system.h + * + * This include file contains information that is included in every + * function in the test set. + * + * COPYRIGHT (c) 1989-1997. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may in + * the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include + +/* functions */ + +rtems_task Init( + rtems_task_argument argument +); + +rtems_task test_task( + rtems_task_argument my_number +); + +void +destory_all_tasks( + const char *who +); + +boolean status_code_bad( + rtems_status_code status_code +); + +void test1(); +void test2(); +void test3(); + +/* configuration information */ + +#include /* for device driver prototypes */ + +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define TASK_ALLOCATION_SIZE (5) +#define CONFIGURE_MAXIMUM_TASKS rtems_resource_unlimited(TASK_ALLOCATION_SIZE) +#define CONFIGURE_EXTRA_TASK_STACKS (75 * RTEMS_MINIMUM_STACK_SIZE) + +#define CONFIGURE_MAXIMUM_USER_EXTENSIONS (5) + +#include + +/* + * Keep track of the task id's created, use a large array. + */ + +#define MAX_TASKS (1000) +#define TASK_INDEX_OFFSET (1) + +extern rtems_id task_id[MAX_TASKS]; + +/* + * Increment the task name. + */ + +#define NEXT_TASK_NAME(c1, c2, c3, c4) \ + if (c4 == '9') { \ + if (c3 == '9') { \ + if (c2 == 'z') { \ + if (c1 == 'z') { \ + printf("not enough task letters for names !!!\n"); \ + exit( 1 ); \ + } else \ + c1++; \ + c2 = 'a'; \ + } else \ + c2++; \ + c3 = '0'; \ + } else \ + c3++; \ + c4 = '0'; \ + } \ + else \ + c4++ \ + + +/* end of include file */ diff --git a/testsuites/samples/capture/test1.c b/testsuites/samples/capture/test1.c new file mode 100644 index 0000000000..cfe6abae5c --- /dev/null +++ b/testsuites/samples/capture/test1.c @@ -0,0 +1,270 @@ +/* Test1 + * + * This test uses creates a number of tasks so the capture engine + * can show a trace. + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * COPYRIGHT (c) 1989-1997. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may in + * the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include "system.h" +#include +#include + +#include +#include + +static volatile int capture_CT1a_deleted; +static volatile int capture_CT1b_deleted; +static volatile int capture_CT1c_deleted; + +static void +capture_wait (uint32_t period) +{ + rtems_task_wake_after (TOD_MICROSECONDS_TO_TICKS (period * 1000)); +} + +/* + * CT1a: Claim the mutex and then wait a while then wake + * up and release the mutex. While this task waits with + * the mutex another higher priority task is started that + * just loops using all the processing time. It is not until + * another even higher priority thread blocks on the mutex + * does this task get raised to that priority and so + * releases the mutex. This will allow us to capture the + * action of priority inversion. + */ +static void +capture_CT1a (rtems_task_argument arg) +{ + rtems_id mutex = (rtems_id) arg; + rtems_status_code sc; + + sc = rtems_semaphore_obtain (mutex, RTEMS_WAIT, 0); + + if (sc != RTEMS_SUCCESSFUL) + fprintf (stdout, "error: CT1a: mutex obtain: %s\n", + rtems_status_text (sc)); + + capture_wait (2500); + + sc = rtems_semaphore_release (mutex); + + if (sc != RTEMS_SUCCESSFUL) + fprintf (stdout, "error: CT1a: mutex release: %s\n", + rtems_status_text (sc)); + + capture_CT1a_deleted = 1; + + rtems_task_delete (RTEMS_SELF); +} + +static void +capture_CT1b (rtems_task_argument arg) +{ + volatile int i; + + while (!capture_CT1c_deleted) + i++; + + capture_CT1b_deleted = 1; + + rtems_task_delete (RTEMS_SELF); +} + +static void +capture_CT1c (rtems_task_argument arg) +{ + rtems_id mutex = (rtems_id) arg; + rtems_status_code sc; + + sc = rtems_semaphore_obtain (mutex, RTEMS_WAIT, 0); + + if (sc != RTEMS_SUCCESSFUL) + fprintf (stdout, "error: CT1c: mutex obtain: %s\n", + rtems_status_text (sc)); + + capture_wait (500); + + sc = rtems_semaphore_release (mutex); + + if (sc != RTEMS_SUCCESSFUL) + fprintf (stdout, "error: CT1c: mutex release: %s\n", + rtems_status_text (sc)); + + capture_CT1c_deleted = 1; + + rtems_task_delete (RTEMS_SELF); +} + +static void +capture_test_1 (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) +{ + rtems_status_code sc; + rtems_name name; + rtems_id id[3]; + rtems_id mutex; + int loops; + + capture_CT1a_deleted = 0; + capture_CT1b_deleted = 0; + capture_CT1c_deleted = 0; + + name = rtems_build_name('C', 'T', 'm', '1'); + + sc = rtems_semaphore_create (name, 1, + RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | + RTEMS_INHERIT_PRIORITY, + 0, &mutex); + + if (sc != RTEMS_SUCCESSFUL) + { + fprintf (stdout, "error: Test 1: cannot mutex: %s\n", + rtems_status_text (sc)); + return; + } + + name = rtems_build_name('C', 'T', '1', 'a'); + + sc = rtems_task_create (name, 102, 2 * 1024, + RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, + RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR, + &id[0]); + + if (sc != RTEMS_SUCCESSFUL) + { + fprintf (stdout, "error: Test 1: cannot create CT1a: %s\n", + rtems_status_text (sc)); + rtems_semaphore_delete (mutex); + return; + } + + sc = rtems_task_start (id[0], capture_CT1a, (rtems_task_argument) mutex); + + if (sc != RTEMS_SUCCESSFUL) + { + fprintf (stdout, "error: Test 1: cannot start CT1a: %s\n", + rtems_status_text (sc)); + rtems_task_delete (id[0]); + rtems_semaphore_delete (mutex); + return; + } + + capture_wait (1000); + + name = rtems_build_name('C', 'T', '1', 'b'); + + sc = rtems_task_create (name, 101, 2 * 1024, + RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, + RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR, + &id[1]); + + if (sc != RTEMS_SUCCESSFUL) + { + fprintf (stdout, "error: Test 1: cannot create CT1b: %s\n", + rtems_status_text (sc)); + rtems_task_delete (id[0]); + rtems_semaphore_delete (mutex); + return; + } + + sc = rtems_task_start (id[1], capture_CT1b, 0); + + if (sc != RTEMS_SUCCESSFUL) + { + fprintf (stdout, "error: Test 1: cannot start CT1b: %s\n", + rtems_status_text (sc)); + rtems_task_delete (id[1]); + rtems_task_delete (id[0]); + rtems_semaphore_delete (mutex); + return; + } + + capture_wait (1000); + + name = rtems_build_name('C', 'T', '1', 'c'); + + sc = rtems_task_create (name, 100, 2 * 1024, + RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, + RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR, + &id[2]); + + if (sc != RTEMS_SUCCESSFUL) + { + fprintf (stdout, "error: Test 1: cannot create CT1c: %s\n", + rtems_status_text (sc)); + rtems_task_delete (id[1]); + rtems_task_delete (id[0]); + rtems_semaphore_delete (mutex); + return; + } + + sc = rtems_task_start (id[2], capture_CT1c, (rtems_task_argument) mutex); + + if (sc != RTEMS_SUCCESSFUL) + { + fprintf (stdout, "error: Test 1: cannot start CT1c: %s\n", + rtems_status_text (sc)); + rtems_task_delete (id[2]); + rtems_task_delete (id[1]); + rtems_task_delete (id[0]); + rtems_semaphore_delete (mutex); + return; + } + + loops = 15; + + while (!(capture_CT1a_deleted || capture_CT1b_deleted || + capture_CT1c_deleted) && loops) + { + loops--; + capture_wait (1000); + } + + if (!loops) + { + fprintf (stdout, "error: Test 1: test tasks did not delete\n"); + rtems_task_delete (id[2]); + rtems_task_delete (id[1]); + rtems_task_delete (id[0]); + } + + sc = rtems_semaphore_delete (mutex); + if (sc != RTEMS_SUCCESSFUL) + fprintf (stdout, "error: Test 1: deleting the mutex: %s\n", + rtems_status_text (sc)); +} + +static rtems_monitor_command_entry_t capture_cmds[] = +{ + { + "test1", + "usage: \n", + 0, + capture_test_1, + { 0 }, + 0 + } +}; + +void setup_tasks_to_watch () +{ + int cmd; + for (cmd = 0; + cmd < sizeof (capture_cmds) / sizeof (rtems_monitor_command_entry_t); + cmd++) + rtems_monitor_insert_cmd (&capture_cmds[cmd]); +} diff --git a/testsuites/samples/configure.ac b/testsuites/samples/configure.ac index bf19dbe2e9..3e7636b37e 100644 --- a/testsuites/samples/configure.ac +++ b/testsuites/samples/configure.ac @@ -75,5 +75,6 @@ base_mp/node2/Makefile iostream/Makefile cdtest/Makefile pppd/Makefile +capture/Makefile ]) AC_OUTPUT -- cgit v1.2.3