![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Using the Tasking Logic Analyzer The following topics are discussed in this document:
- Overview
- Apex and the Tasking Logic Analyzer
- Getting Started
- Runtime Library Instrumentation
- User Control
- Analysis
- apex_trace_driver Configuration
- Debugger Support
- Task Trace Visualizer —— apex_trace_driver and apex_xtrace
- Example
OverviewNote: For embedded products, the Tasking Logic Analyzer is available only with the Apex for Rational Exec products.
The Tasking Logic Analyzer allows the Apex Ada programmer to trace task execution and analyze it using saved event files or, by using the debugger, to examine the most recent events. The Trace tool is provided to display event data in such a way as to help in understanding the behavior of the tasks in a number of different ways.
The software consists of an instrumented Ada runtime library, Ada packages to support user program control of logging, support within the Ada debugger, apex_debug, for display of interpreted events and an analysis program, apex_trace_driver.
apex_trace_driver can analyze trace information to generate a text interpretation of the raw events, statistical analysis of tasking behavior, or it can output the data to an X-windows program, apex_xtrace, for graphical display.
apex_debug can also output the current trace buffer to apex_xtrace.
Figure 1 shows an overview of the Tasking Logic Analyzer. An instrumented Ada program writes events to an event buffer. This can either be read by apex_debug or written to a file by user inserted subroutine calls or automatically on program completion. apex_debug and apex_trace_driver use similar analysis to interpret the event buffer or trace file(s) respectively. Using the program's load module and Ada libraries, the logged information is interpreted into Ada names and source positions and output to a Key file and to a temporary trace file (which may consist of a concatenation of multiple trace files). The Key file is a text file providing a list of conversions from numbers to names. The Key file and temporary trace file are inputs to apex_xtrace, an X-windows program that can analyze the data and express it graphically.
Figure 1 Overview of Tasking Logic Analyzer Software
![]()
Apex and the Tasking Logic AnalyzerThe Tasking Logic Analyzer is integrated into the Apex directory structure.
The software can be found in your APEX_HOME area under the subdirectory bin. The tools are called apex_trace_driver and apex_xtrace.
There exists a subsystem, $APEX_BASE/ada/rts_trace.ss, which contains Ada packages which allow the user program control of tracing. It also contains several examples referenced within this document.
rts_trace.ss
Support packages
event_log_manager.1.ada
event_log_manager.2.ada
krn_event_log_manager.1.ada
krn_event_log_manager.2.ada
Examples
own_buffer.2.ada
phil.2.ada
phil2.2.adaOther packages of interest for tracing are:
rational.ss
v_i_trace.1.ada
v_i_krn_trace.1.adawhich specify the standard runtime events and some of the low-level logging information.
Trace configuration data can be configured with parameters in the user library, $APEX_BASE/ada/usr_conf.ss/<view>/v_usr_conf.2.ada.
Getting StartedThis section walks the user through using the Tasking Logic Analyzer. It is intended to get you using the tool quickly. Explanations are brief. For more detail, please refer to other sections of the manual.
This section assumes you have been able to compile and run an Ada program.
Link in an Instrumented Runtime
When you select the Compile > Link menu item, a Link dialog will be presented. Select the Alternatives Icon button next to the Options > prompt box. Select on the -tracing runtime item and it will appear as an option in the prompt box. Select the OK button and the link will proceed.
Or, from a shell command line, add the option -tracing runtime to your link command. For example, assuming test1.2.ada is your main program source, add the following line to your link command:
apex link -tracing runtime test1.2.ada
Loading a Tracing Kernel
(For Embedded Systems Only) A special kernel must be loaded to support event tracing. Your default kernel is built in the Board Specific krn_conf area and has the name v_krn_main. In the same view should be the file v_ktr_main. This is the tracing kernel. You should download this, either using the Tools > Targets menu option or the File > Download option.
You can also use apex_download to load the kernel from the command line.
Turn Tracing On and Run Your Program
You still have the option of running your relinked program without tracing although it will run slightly slower. This is so that users trying to track down problems can check that program behavior is the same as when linked without tracing.
To enable tracing, select the File > Run... menu item. Select the button labelled "collect trace data" then select OK.
Or, from the shell command line use the csh command,
setenv APEX_TRACE
or, on some more restrictive host systems
setenv APEX_TRACE 1
test1
Note, you will have to perform the setenv command each time you login.
To disable tracing from the shell, enter the csh command
unsetenv APEX_TRACE
Process log files with an X-Window system
To view the trace data, select the Tools > Trace menu item on your view window.
A dialog window will appear. Select for graphic output, then select OK.
A main window will appear with the title Apex Trace. The graphs of immediate interest are to be found under the View menu item.
Restarting the X-Window version of apex_trace_driver
Several new files will appear in your view directory after running the X window version of apex_trace_driver. These have filenames of the form
test1.replay.123456
test1.key.123456
test1.trace.123456where test1 is the name of your main program unit and the 123456 represents a unique 6-character string generated by the mktemp() UNIX system service.
After you exit the trace graphical tool (File > Exit), you can restart the tool at any time by invoking the replay script from a shell prompt. For example:
test1.replay.123456
Alternatively, the Tools > Replay Trace menu item invoked from the View window allows you to select a replay file.
At the prompt box "replay file name" enter the name of the replay file or use the Alternatives Icon to select from all files of the form *.replay.*
Process log files without an X-Window system
From a shell command line, you can still view statistical analysis and a readable text version of the raw events in the log file.
Assuming you are in an Apex shell:
apex_trace_driver test1 LOG_FILE >tmp
will output the text interpretation of your events into the file tmp.
apex_trace_driver -s test1 LOG_FILE >stat
will output a statistical analysis of your events into file stat.
Runtime Library InstrumentationThe following topics are discussed in this section:
Overview
There are two types of instrumentation. The main type is Runtime Library Instrumentation and is implemented using an instrumented Ada Runtime which is included in the user program by relinking the load module. Trace events are generated by an instrumented Ada Runtime which is included in the user program by relinking the executable. It is also possible to log user events by adding subroutine calls to your code.
Events are saved as records. The first part of the record is common to all types of event and the latter part is variant.
logged_event: Kind_of_Event; Which variant (Runtime, header, user, kernel). node : integer; Identifies the process on which the current task is running. task_seqnum : integer; The current task sequence number. time_stamp : microseconds; An integer type.A standard set of runtime events is supported. In addition, the user can log up to 20 user defined event types by the same mechanism. User events are inserted as subprogram calls in the user's program and are logged in the buffer interspersed with the runtime events.
The events are defined in the standard directory in package V_I_Trace (filename v_i_trace.1.ada).
There are a number of types of events.
- Runtime Events
A set of events considered sufficient to trace the behavior of the Ada runtime. Up to four integer arguments can be saved. These events are embedded in the instrumented runtime library.
- User Events
Can be generated by user code. Stores a 16 byte user comment or 4 integer words. The names can be given any meaning the user wants. There are several standard user events and a group of 20 generic events.
- Header Events
Allow users to store some standard instrumentation data from their programs.
- Kernel Events
The names are specified in package V_I_Krn_Trace. They are designed for internal use by runtime developers.
Runtime Events
The following events are supported. Events ending in _req represent requests from the user's code. They are logged on entry into the task services of the runtime. Events ending in _end are usually logged just before control is returned to the user code.
task_creation_begin task_creation_end simple_entry_call_req simple_entry_call_end timed_entry_call_req timed_entry_call_end timed_entry_call_timeout cond_entry_call_req cond_entry_call_end simple_accept_req simple_accept_end select_req select_else_req select_delay_req select_terminate_req select_end select_else_end select_delay_end select_terminate_end delay_req delay_expired continue_from_delay delay_until_req delay_until_expired continue_from_delay_until rte_exception Implicit exception raise_req Explicit raise exception_handler Control passed to handler. task_begin_req task_terminate_req task_terminate task_abort_req task_abort task_semaphore_wait task_semaphore_wait_complete task_semaphore_wait_timeout task_semaphore_signal memory_allocate memory_deallocate
-- Non-threaded runtime scheduling events switch_to switch_to_idle_task switch_to_rendezvous_in_called New task's code is executed without full context switch. Fast rendezvous optimization.
-- Threaded runtime scheduling events kernel_signal kernel_wait kernel_wait_complete kernel_signal_wait kernel_signal_wait_complete kernel_timed_wait kernel_timed_wait_complete kernel_timed_wait_timeout
interrupt_entry interrupt_exit
breakpoint Inserted by apex_debug to explain large time gap
This list will expand in the future for specialized runtime use.
User Events
The following user events are supported.
start_of_sequence User defined. start_process Application initiates a process (a process is user defined) end_of_process Task completes a process (a process is user defined) start_buffer_flush Inserted automatically before calling the user-supplied "nearly-full" callout routine. end_buffer_flush Inserted automatically in the start of a new buffer after calling the user-supplied "nearly-full" callout routine. process_base_time Process established base timeThe following event names can be used as required by the user.
event1, event1a event2, event2a event3, event3a event4, event4a event5, event5a event6, event6a event7, event7a event8, event8a event9, event9a event10, event10a
no_event
You can log these events by instrumenting programs with calls to a subprogram supplied with the trace software. Different versions allow you either to log a fixed length (16 character) string or 0 to 4 integers.
Header Events
There is one form of header event. Its format is specified in package V_I_Trace. As well as the usual fields, the following are defined
These are user supplied items, which are designed to be of use in documenting test runs.
User ControlThe following topics are discussed in this section:
- Steps
- Relinking Your Program
- Debugger Control (overview)
- Using Program Control
- Callout Routines
- Buffer Handling
Steps
There are several steps you must take to obtain trace data. You must at least relink your program with a tracing option.
After relinking you have several options.
- 1 . If you simply want to generate a default set of Runtime Events, you can either use the File > Run... "collect trace data" button or set the APEX_TRACE environment variable. At the end of program execution, the current event buffer will be transferred to the default trace file in your current working directory.
- 2 . If you run your program under the debugger, apex_debug, invoked either with the "collect trace data" button set, or with the APEX_TRACE environment variable set, you have a number of control options that you can exercise at any breakpoint. You can enable or disable any runtime events and you can dump the current event buffer to the file of your choice.
- 3 . You can control logging by modifying your program to call subprograms in the package Event_Log_Manager which is found in the rts_trace.ss subsystem. This package supports a large number of configuration and control options. It also supports logging of user generated events in the same buffer as the Runtime events. This method offers you the greatest control and flexibility, but involves the most work on your part.
Relinking Your Program
The following command line option control tracing.
Option Name Dialog Action
- tracing runtime link dialog affects linking
In order to generate runtime logs, you must link your program with an instrumented runtime.
In order to do this you must link with at least the following option:
If you do not want to generate runtime data, you do not need to link in the instrumented runtime, but you do need to recompile and relink with the normal runtime.
If you have added calls to the package Event_log_Manager, you need to add a view from the rts_trace.ss subsystem to your imports.
The default linking option is no automatic tracing but this doesn't mean you can't trace. If you simply use Event_log_Manager to generate user events and to do your own log file creation and save of event buffers to that file. If you save your own buffer, you will not want to use the File > Run... "collect trace data" button or APEX_TRACE environment variable or you will get two buffer saves.
You can alter the default name of the trace file by using the shell environment variable APEX_TRACE_FILENAME.
% setenv APEX_TRACE_FILENAMEmy_log_file
You can change the default size of the event buffer (4096 events) by using a pragma MAIN statement in your main program.
pragma MAIN(TRACE_BUFFER_SIZE => 8192);
For more information on pragma Main, see the Ada Compiler Reference Guide.
Alternatively, the package Event_Log_Manager allows you to control these and more.
Debugger Control (overview)
Assuming you have either set APEX_TRACE or otherwise arranged to log trace events, you can perform a certain amount of logging control from the debugger, apex_debug.
The following actions are possible.
- 1 . Enable or disable all or single runtime events using the te - trace enable and td - trace disable commands.
- 2 . Dump the current event buffer to the file of your choice using the to - trace output command.
- 3 . Pass the current event buffer and a key file of conversions from numbers to names to the X-window display program apex_xtrace.
- 4 . Browse the event buffer in several different formats. The main formats are concise (one event per line) and verbose. You can also browse in source mode which uses caller's return addresses logged to let you replay your events in the order of logging, modifying the current focus of the debugger so that you "see" your program being replayed.
Using Program Control
You can obtain maximum control of logging by using the package Event_Log_Manager in your actual program. Event_Log_Manager is packaged in the subsystem rts_trace.ss. You need to add a view of this subsystem to your Imports. The source of the package specification is to be found in Event_Log_Manager.1.ada
Event_Log_Manager supports the control of logging, allowing you to enable or disable logging of events, specify one or more log files, open or close these log files, and obtain event data. Event_Log_Manager depends on the packages v_i_trace.1.ada and v_i_krn_trace.1.ada which are in the rational.ss subsystem. These packages specify the event names, the event record format and a user configuration format.
Events are logged in a common event buffer, by a common logging routine. The default address and size of the event buffer can be overridden by the user.
The simplest use of event logging is to add the following statements to your program.
with Event_Log_Manager;
Where you wish to start logging:
Event_log_Manager.Enable_Logging_of_All_Runtime_Events; Event_log_Manager.Start_Logging_RTS_Events;
Where you wish to stop logging:
Event_log_Manager.Stop_Logging_RTS_Events;
Note that the routines Start_All_Logging and Stop_All_Logging can also be used. These routines combine the enable/start functions.
These statements cause runtime events to be collected in the default event buffer. When the buffer fills, it is filled from the start again (that is, it is treated as a circular buffer). The flag, V_I_Trace.Log_Overflowed, is set to True. You can browse these events from the debugger.
As described in the debugger documentation, the events can be saved to a file from the debugger. If you want to control the file name, or to run without the debugger, add the following (or similar) statements to your program.
Log_File: Event_Log_Manager.Log_File_Type;
Before logging starts (or after it completes):
Event_Log_Manager.Open(Log_File, Event_Log_Manager.Out_File, your_file);
Event_log_manager.Save_event_log(Log_file); Event_log_manager.Close(Log_file);
Package Event_Log_Manager offers a number of other control subprograms, e.g., the ability to support several log files, to delete files or to interpret your own events.
Package V_I_Trace contains a configuration table which enables you to customize the event collection. This table is an optional input to the subprogram:
event_log_manager.Init_logging(configuration: a_trace_configuration_t);
Init_Logging can be called in 2 different ways.
- 1 . The procedure Trace.Start_Tracing is called during runtime startup. If you are using apex_trace_driver, a configuration table is passed to Init_Logging, otherwise a null pointer is passed and default setup is done. The call to V_I_Trace.Init_Logging is equivalent to a call to Event_Log_Manager.Event_Logging.
- 2 . Alternately, you can call it with a configuration table of your own to override default settings. This should be done while events are not being collected, that is, before event collection is enabled. One advantage of this is that you do not get events from run-time and user program elaboration if you do not want them.
The declaration of the configuration table is shown below:
type trace_configuration_t is record -- User configurable Runtime_log : Runtime_enables; event_buffer_size : integer; -- number of records event_buffer : a_event_buffer_t; -- null is do not care wrap_around : boolean; hardware_logging : boolean; disable_locking : boolean; -- single processor, -- not logging interrupts nearly_full_callout : system.address; -- no_addr is do not care nearly_full_index : integer; get_time_callout : system.address; -- used in user code and -- task services krn_get_time_callout : system.address; -- callable from kernel log_callout : system.address; -- replace logging routine
-- Other items are not for user use. ... end record; type a_trace_configuration_t is access trace_configuration_t;It offers you the ability to do the following:
- 1 . Automatically enable runtime event collection.
- 2 . Specify an alternate size for the event buffer. If you do not supply an address, a buffer will be allocated from the heap.
- 3 . Specify an address for the event buffer.
- 4 . Specify whether collection should wrap around to the start of the buffer when it is full, or whether it should stop when the index points past the end of the buffer. The default behavior is to wrap around.
- 5 . Specify a callout routine to handle a nearly full buffer.
- 6 . Specify the event buffer index at which the callout routine is to be called.
- 7 . Specify an alternate function to handle time measurement. The specification should match:
function get_time return event_log_manager.microseconds;
The following is adequate if you do not want timing information.
function get_time return event_log_manager.microseconds is begin return 0; end get_time;
- 8 . Disable locking of the event buffer. Could be used in a single processor runtime, which does not use interrupts or time-slicing, to reduce the overhead of logging.
- 9 . Specify your own event logging routine. You will have to organize your own buffering and wrap around.
The specification should match
procedure log(event : v_i_trace.event);
Callout Routines
You should note that the callout routines are called from within the kernel. They can only execute a very limited number of things. In particular, they cannot:
- Call I/O packages.
- Allocate memory.
- Raise exceptions.
- Access stack data.
You should declare all variables used by the callout program at the library level (in a package's outer level).
Buffer Handling
If you want to analyze your own event buffers in the same program that collects the data, you can avoid having to save the buffers to disk and then reading them in again.
Buffer handling is implemented using the following subprograms.
Sets up read pointers. You can specify an alternative buffer or buffer size. If no arguments are supplied, the default buffer is accessed.
Returns false while records are unread.
function End_Of_Buffer return boolean;
Reads the next event. A version of this routine allows you to specify the index in the buffer if you do not wish to read serially.
procedure Read_Log_Event_From_Buffer (Item : out Event); procedure Read_Log_Event_From_Buffer (Index : in integer; Item : out Event);
Resets pointers so that future data collection starts with new data
procedure Reset_Buffer;;
A typical usage of buffer handling is illustrated below.
Open_Buffer; while not End_Of_Buffer loop Read_Log_Event_From_Buffer(Item); -- Analyze item using other -- event_log_manager subprograms. ... end loop; Reset_Buffer;
Remember to stop event logging before you start analysis. The procedure Reset_Buffer resets collection points so that you can continue collection with a fresh buffer.
Example: Configuring Buffer Size
The example below demonstrates the use of a configuration record to override the default event buffer and to set your own buffer size. An array of booleans is used to enable event collection at the time of the call to the Init_Logging routine. Note that no attempt has been made to save the events to a file. You can monitor the events from the debugger. Note that the buffer will be empty until after the first rendezvous call has been made.
with text_io; with event_log_manager; with unchecked_conversion; with system; procedure own_buffer is config : event_log_manager.a_trace_configuration_t; static_enables : Event_log_manager.runtime_enables := Event_log_manager.runtime_enables'(others => true); EBS : constant integer := 64; -- Number of events type my_event_buffer is array (1..EBS) of Event_log_manager.event; type event_buffer_pointer is access my_event_buffer; event_buffer : event_buffer_pointer; function to_event_buffer is new unchecked_conversion (event_buffer_pointer, Event_log_manager.a_event_buffer_t); task a is entry a1; end a; task body a is begin loop select accept a1 do delay 0.0001; end a1; or terminate; end select; end loop; end a; begin -- Get your own event buffer event_buffer := new my_event_buffer; -- Initialize configuration record config := new event_log_manager.trace_configuration_t; config.runtime_log := static_enables; config.event_buffer_size := EBS; config.event_buffer := to_event_buffer(event_buffer); config.wrap_around := true; config.nearly_full_index := 0; config.nearly_full_callout := system.no_addr; config.hardware_logging := FALSE; config.disable_locking := FALSE; config.get_time_callout := system.no_addr; config.krn_get_time_callout := system.no_addr; -- Start logging event_log_manager.init_logging(config); for i in 1..4 loop a.a1; -- Some events will be in the buffer by now end loop;
end own_buffer;
AnalysisThe following topics are discussed in this section:
For instructions on invoking apex_trace_driver see Task Trace Visualizer —— apex_trace_driver and apex_xtrace.
Raw text output
The simplest method of analysis is to obtain a text representation of the logged events. This can be done via apex_debug or apex_trace_driver.
apex_debug can analyze an event buffer and show raw text output in two formats: concise, or verbose. In both cases, the asterisk on the left hand side indicates the current event. The default format is concise. To view concise raw trace output from apex_debug type:
tl
This command generates output similar to the following:
Item Task Event Arg1 Arg2 Arg3 ---- ---- ----- ---- ---- ---- 1265 203 Continue_From_Delay tsa:0043402c -- 1266 203 Simple_Entry_Call_Req t202 en:1 pc:004341dc 1267 203 Select_Terminate_End en:1 -- 1268 203 Switch_To_Rendezvous t202 tsa:00433b74 * 1269 203 Switch_To t202 -- >Argument types are identified in concise mode as follows.
Address - adr:00414470 - as in memory allocated Boolean - TRUE or FALSE Caller - pc:00413ff4 - return address of call to task service Entry - en:1 - task entry Exception - exc:1000c0cc - an exception identifier Integer - 100 Priority - pr:10 Semaphore - sem:10462300 Size - size:19 - as in size of memory allocated Task - t14 Task start address : tsa:00414470 Time - 0.004500 s - as in delay (units seconds)apex_debug can also show analyzed information in verbose format. To set verbose format, type
set trace v on
tl
This command generates output similar to the following.
Item Time Current task ---- ---- ------------ 1266 0.434800 first_task (203) Event => Simple_Entry_Call_Req Task => heap_allocation (202) Entry => more_heap Caller => first_task, path/tasks0.2.ada, line 95 (004341d4) * 1267 0.434900 first_task (203) Event => Select_Terminate_End Entry => do_some_workapex_trace_driver generates raw text output in verbose mode only. The output is identical to the verbose formatted output from apex_debug except that there is no asterisk.
Task statistics
apex_trace_driver can generate statistics about task usage. Here is a fragment of some output
Statistics for program tasks0 ----------------------------- Time range in event file 0.159000 to 49.445900 secs. Time range analyzed 0.159000 to 49.445900 secs. Events in event file 2404 Events analyzed = 2404 Task count = 25 Process count = 1 Tasks created = 46 Tasks activated = 23 Tasks terminated = 20 Tasks aborted = 0 Context switches = 605 Idle task time = 47.276707 secs. (95.921%) Total heap allocations = 524288 bytes. Task # 0 <idle task> Resumes = 42 Time in execution = 47.276707 secs. (95.921%) Task # 1 Sequence number = 1 <main program> Calls = 32 Accepts = 0 Delay requests = 1 Requested delay time = 0.001000 secs. Actual delay time = 1.018803 secs. Resumes = 16 Allocated = 524288 bytes. Deallocated = 0 bytes. Time in execution = 0.300405 secs. ( 0.610%) Task # 2 Sequence number = 2 autonomous Calls = 8 Accepts = 1 Delay requests = 16 Requested delay time = 13.107000 secs. Actual delay time = 28.116596 secs. Resumes = 23 Allocated = 0 bytes. Deallocated = 0 bytes. Created by <main program> (1) Created at tasks0, /vc/pc/apex/learn.ss/myview.wrk/tasks0.2.ada, line 36 (000a9434) Creation time = 0.378800 secs. Activation time = 0.425500 secs. Termination time = 45.286301 secs. Time in execution = 0.048806 secs. ( 0.099%) . . and so onGraphical Visualization
Both apex_trace_driver and apex_debug can invoke a program called apex_xtrace which can take trace files together with a key file of conversion data and reduce them to several standard displays.
The provided displays are as follows. Examples of each of these displays can be found in Task Trace Visualizer —— apex_trace_driver and apex_xtrace.
A bar graph display of tasks in execution versus time.
A bar graph display of the underlying processes used to implement tasks. It is used to demonstrate multithreaded Ada programs.
A plot of call requests and their corresponding completions. The requests are shown as arrows from the caller to the called. Completion is shown as a dotted line arrow in the reverse direction. The Task Timeline can be superimposed on this display
In multithreaded runtimes, signals and waits are used to implement Ada rendezvous. This is a plot of tasks versus time showing lines from the signalling task to the task whose wait completes on reception of the signal showing rendezvous activity. The Task Timeline can be superimposed on this display.
Shows the number of tasks active simultaneously. This display can also be shown as a histogram as percentage utilization of the number of processes assigned to the Ada program.
Shows requests to allocate space on the heap and requests to free space on the heap, using allocators and Unchecked_Deallocation respectively.
An interpretation similar to the apex_debug output. Data can be selected by time range from any of the other displays. The events stored in the trace logs can be displayed directly in a human readable, but event-oriented form.
apex_trace_driver and the debugger communicate with apex_xtrace through two files, a key file and a temporary trace file. The trace file may be a concatenation of several files.
The key file is a text file and consists of conversions from numerical logged information to Ada and source information. It contains conversions for Tasks, Nodes (Processes), Callers (return addresses), Called (subprograms called), Entries, and Exceptions.
An example with some lines removed shows conversions from task sequence number to task name, return addresses to calling locations, tasks:entry numbers to entry names and exception addresses to exception names. This information is available to apex_trace_driver and apex_debug but not to apex_xtrace except via the key file.
Tasks 0= <idle task> 1= <main program> 2= test1.c . . Callers 004397c4= test1, /dev/base.ss/my.wrk/test1.2.ada, line 40 (004397bc) 0043987c= test1, /dev/base.ss/my.wrk/test1.2.ada, line 42 (00439874) 00439924= test1, /dev/base.ss/my.wrk/test1.2.ada, line 133 (0043991c) 004399cc= test1, /dev/base.ss/my.wrk/test1.2.ada, line 164 (004399c4) 00439a20= test1, /dev/base.ss/my.wrk/test1.2.ada, line 233 (00439a18) . . Entries 8:1= c1 7:1= c1 6:1= c1 5:1= c1 . . Exceptions 1000c0cc= constraint_error 1000b578= MY_EXCEPTIONThese key files together with their corresponding temporary binary trace files may clutter up your working area. You should clear them out every so often. Their names take the form:
where unit is the name of the main program unit, type can be replay, key or trace and unique_id is a 6 character unique string generated by the UNIX mktemp() system service. For example, for unit test1:
test1.replay.123456 a csh script that can be used to replay apex_xtrace
test1.key.123456 the key file
test1.trace.123456 the binary trace file
apex_trace_driver ConfigurationThe following topics are discussed in this section:
apex_xtrace is configured so that it does not require a resource file. It uses fallback resources to generate a standard look as defined below. If you wish to modify the look of the tool, you can supply your own resource file to be placed in a private file (setenv $XENVIRONMENT file) or in a central location (/usr/lib/X11/app-defaults/A_trace).
The following listing describes the standard look.
Resources for task visualization
! All lines are commented out.
! if you do not like colors - uncomment and try your own. (No trailing ! spaces) !A_trace*task0Color: black !A_trace*task1Color: blue !A_trace*task2Color: green !A_trace*task3Color: orange !A_trace*task4Color: yellow !A_trace*task5Color: red !A_trace*task6Color: cyan !A_trace*task7Color: magenta !A_trace*task8Color: lime green !A_trace*task9Color: pink !A_trace*task10Color: brown
! If you do not like labels uncomment and change. !A_trace*processCountLabel: Process count..... !A_trace*taskCountLabel : Task count........ !A_trace*maxTimeLabel : Max time (secs)... !A_trace*traceFileLabel : Trace file........ !A_trace*traceFormatLabel : Trace format......
!A_trace*task_colors*BorderWidth : 0
! Main window !A_trace*status.BorderWidth : 1 !A_trace*status*display.BorderWidth : 0 !A_trace*status*display.ShadowThickness : 0
! The buttons on graphs !A_trace*command*BorderWidth : 0 !A_trace*command.selections*BorderWidth : 1
! The drawing canvas for the graphs. !A_trace*canvas*BorderWidth : 1 !A_trace*canvas.unittype : 1000TH_INCHES !A_trace*canvas.height : 250 !A_trace*canvas.width : 800
!For a remote printer, modify REMOTE_HOST, REMOTE_PATH, PRINTER !A_trace*printLine1: xwd -frame | xpr -device ps > psdump\n !A_trace*printLine2: rcp psdump REMOTE_HOST:REMOTE_PATH\n !A_trace*printLine3: /usr/ucb/rsh REMOTE_HOST lpr -P PRINTER psdump\n !A_trace*printLine4: /usr/ucb/rsh REMOTE_HOST rm psdump\n !A_trace*printLine5: rm psdump\n
!For a local printer modify PRINTER !A_trace*printLine1: xwd -frame | xpr -device ps > TEMP\n !A_trace*printLine2: \n !A_trace*printLine3: lpr -P PRINTER TEMP\n !A_trace*printLine4: rm TEMP\n !A_trace*printLine5: \nWidget names
This section contains a list of the more important widgets used in the apex_xtrace tool. If you wish to change resources within a specific dialog, you can use these names to specify that dialog. For example, to change the default size for the heap usage display, you can adapt the resource file listed above as follows.
A_trace*heap_usage*canvas.height: 400
This makes the canvas 4 inches high (approximately) instead of the default 2.5 inches.
Widget Name Explanation
Application Shell A_trace Main window framework Main form. menubar Main menubar. status Status board. File selection trace_filename_selection File:Open Format selection format After a file is selected. Dump File selection dump_filename_selection File:Open Dump File Print control print File:Print Graphs Form dialogs under the View menu item. task_framework Task timeline. node_framework Process bargraph. call_requests_and_returns Call requests and returns. sigwait_framework Signals and waits task_activity Activity heap_usage Heap usage. selected_framework Raw trace text display canvas drawing area command command button row Display Organization Options:Display organization Organization menubar colors_scroll tasks_scroll nodes_scroll Time selection popup dialog time_selection Options:Time Range Selection Error popup dialog errorHelp Files
apex_xtrace interfaces to the Online Reference documentation to display help information.
Selection of the Help button on the main menu bar will give you the options:
- On Context
- On Help
- On Window
- On Version
The last 3 are fairly self-explanatory, bringing up help pages on the Help system, the main window and on the software version. The On Context selection changes the mouse cursor to a question mark so that if you click on any part of the current apex_xtrace display, the help server will be invoked to show a help file on that subject. If you wish help on a menu item from a pull down menu, you will have to use the Help key on your keyboard. The Help key should also work after a button selection on other parts of the application windows.
Warning: If you are using OpenWindows, you may have to modify your .xintrc file in your server to disable OpenWindows' use of the Help key.
The following lines illustrate a typical extract from .xintrc:
#Install function key "F1" as an Open Look "Help" key. #This precludes its use by applications #If your applications use F1 for anything else, comment #out the following line xmodmap -e 'keysym F1 = Help'.
Comment out the xmodmap line by inserting a # at the start of the line.
Debugger SupportIf you debug a program that is logging events, there is a set of commands to allow you to browse your event buffer when you hit a breakpoint. There are also commands to allow you to control logging and to dump the event buffer to a file.
The following topics are discussed in this section:
- Commands for Traversing the Event Buffer
- Control of logging
- Interfacing with apex_xtrace
- Control of Display Format
- Display Modes
- Command Descriptions
- tb - trace back
- td - trace disable
- te - trace enable
- tf - trace forward
- tl - trace list
- tm - trace move
- tn - trace now
- to - trace output
- ts - trace start
- tw - trace window
Commands for Traversing the Event Buffer
The following commands are used to traverse the event buffer
tb trace back
tf trace forward
tl trace list
tm trace move
tn trace now (end of buffer)
ts trace start (start of buffer)
tw trace window
Control of logging
enable logging of event, all events if no name supplied.
disable logging of event, all events if no name supplied.
dump event buffer to file. Use previous file if no filename supplied.
To log an event in the current event buffer at a breakpoint, use a command similar to the following.
>p v_i_trace.user_log(v_i_trace.event10, "I put this here."); Procedure returned normally >tl Item Task Event Arg1 Arg2 Arg3 ---- ---- ----- ---- ---- ---- * 149 t0 Event10 I put this here.
Make sure your string is 16 characters long.
Interfacing with apex_xtrace
When you stop at a breakpoint, you can start up apex_xtrace to provide yourself with a graphical display of the events. A precondition is that you should have access to an X-terminal, and have the DISPLAY environment variable set to that terminal's name:
setenv DISPLAY elc-x:0
set trace x
then enter any of the browsing commands:
tl
apex_xtrace will be invoked with a text key file and a temporary trace file as input parameters. If you run to another breakpoint in the debugger and perform another browse command, the apex_xtrace tool will be sent an update. If you do not want this to happen, enter the command
set trace x off
One reason to turn it off is that the graph will now reflect the large amount of time you spent thinking at the breakpoint, so you will see two small vertical bands of events and a large empty gap in between. Use the zoom facility if this happens to you.
Control of Display Format
The following commands provide control of the display format.
set event [number]- set number of events to display in tl - trace list and tw - trace window commands.
The other commands take the form
set trace option [on|off]
Control source mode display. If s on, source oriented browsing is performed. If s off, line mode format is used. If you switch to source tracing mode, the debugger deals only in those events that have a return address saved. This typically means task service (TS_) events where the call was from user code. If source tracing mode is set, the tb - trace back command takes you back to the previous call to a tasking service in the user code and sets the environment to that source location. The effect is similar to that of the cd or cu command on a call stack when you are debugging in screen mode. [Default: off]
Switch from concise to verbose mode. If you switch verbose mode to on (v on), a minimum of 3 lines of text are displayed plus a line for each of the stored arguments. [Default: off]
Start/stop communication with apex_xtrace. [Default: off]
Allow or suppress the display of runtime events when you browse the event buffer. [Default: on]
Allow or suppress the display of call and return profile events when you browse the event buffer. [Default: on]
Allow or suppress the display of basic block profile events when you browse the event buffer. [Default: on]
Display Modes
Concise Mode
Concise mode displays events in a format with one line per event. Times are suppressed, stored information is output in a compressed format.
A typical event, displayed concisely, is shown below
Item Task Event Arg1 Arg2 Arg3 ---- ---- ----- ---- ---- ---- * 189 t7 Simple_Entry_Call_Req t3 en:2 pc:0041416cThe asterisk identifies the current event. Under Arg1 through Arg3 are arguments stored at the event. Tasks are identified by number. These numbers are the task sequence numbers assigned by the Ada run-time.
The lt command tells you more about the task.
>lt 3 Q# TASK ADDR STATUS T dining_room 010087e1c suspended at select ENTRY STATUS TASKS WAITING allocate_seat open - no tasks waiting - etc.
Argument types are identified in concise mode as follows.
Address - adr:00414470 - as in memory allocated Boolean - TRUE or FALSE Caller - pc:00413ff4 - return address of call to task service Entry - en:1 - task entry Exception - exc:1000c0cc - an exception identifier Integer - 100 Priority - pr:10 Semaphore - sem:10462300 Size - size:19 - as in size of memory allocated Task - t14 Task start address : tsa:00414470 Time - 0.004500 s - as in delay (units seconds)Alternatively, you can use the verbose mode of display.
Verbose Mode
Verbose mode displays use the debugger to interpret items such as task sequence numbers and caller return addresses. The saved time is displayed. A typical output is shown below
189 1.971800 philosopher (2) Event => Simple_Entry_Call_Req Task => dining_room (3) Entry => enter Caller => philosopher, /vc/pc/nom/phil.2.ada, line 260 (00414164)
This event tells us that at time 1.971800 seconds, the task philosopher, (line 260 of phil.2.a) made an entry call to Dining_Room.Enter.
Every event contains the time, the task sequence number of the current task and the event identifier. Following the event identifier are from 0 to 4 arguments (depending on the event type).
Source Mode
Source mode ignores events which did not save a caller return address. Usually, only events at the task service level save a return address.
Source level output from commands such as tl - trace list and tw - trace window suppresses the display of some events, such as kernel events that did not store a return address.
If you use vi mode and move around in the trace buffer, the current environment will move also so that you can visualize a replay of a sequence of tasking requests by, for example, doing successive tf - trace forward commands.
Command Descriptions
The following sections describe each of the debugger commands available for use with the Tasking Logic Analyzer. These commands are used to traverse the event buffer.
tb - trace back
Syntax
tb [count
]
Arguments
Description
Move the current event back the number of events specified by count.
>tb Item Task Event Arg1 Arg2 Arg3 ---- ---- ----- ---- ---- ---- * 730 1 Simple_Entry_Call_Req t11 en:1 pc:00439db0 >set trace s on >tb Item Task Event Arg1 Arg2 Arg3 ---- ---- ----- ---- ---- ---- * 727 8 Delay_Req pc:00439448 0.004096 s >tb Item Task Event Arg1 Arg2 Arg3 ---- ---- ----- ---- ---- ---- * 724 5 Delay_Req pc:00439448 0.008192 s >Note that tb operates only on events with caller information when in source mode. This information is identified in concise mode by pc:.
td - trace disable
Syntax
td [event_name
]
Arguments
Description
Trace disable (td) allows the user to suppress event collection for runtime events. If no event name is supplied, all runtime events are disabled. Supplying a single name disables that event. Note, only runtime events can be disabled in this way. User and Header events should be controlled from the user's program.
te - trace enable
Syntax
te [event
]
Arguments
Description
Trace enable (te) allows the user to enable event collection for runtime events. If no event name is supplied, all runtime events are enabled. Supplying a single name enables that event. Note, only runtime events can be enabled in this way. User and Header events should be controlled from the user's program.
tf - trace forward
Syntax
tf [count
]
Arguments
Description
Move the current event forward the number of events specified by count.
>set trace v >tf Item Task Event Arg1 Arg2 Arg3 ---- ---- ----- ---- ---- ---- * 2663 128.590897 Idle task Event => Interrupt_Entry 2 Address => 00438590 > >set trace s on >tf * 2669 128.591995 <signal 2> (16) Event => Simple_Entry_Call_Req Task => end_it'1 (15) Entry => interrupt Caller => +signal_task_proc, (null), line 0 (00447c7c) >Note that tf operates only on events with caller information when in source mode.
tl - trace list
Syntax
tl [count
]
Arguments
Description
Print events up to and including the current event. count can be specified on the command line. If not specified, the count is the default (initially 10). The set event command modifies the default.
The current event is marked with an asterisk.
Example - Concise Mode
>set trace v off >set event 10 >tl Item Task Event Arg1 Arg2 Arg3 ---- ---- ----- ---- ---- ---- 2660 11 Delay_Req pc:00438454 0.009000 s 2661 11 Switch_To_Idle_Task -- -- 2662 11 Switch_To t0(Idle) -- 2663 0 Interrupt_Entry 2 adr:00438590 2664 0 Task_Semaphore_Signal sem:100b62ac -- 2665 0 Interrupt_Exit 2 adr:00438590 2666 0 Task_Semaphore_Signal sem:100b62ac -- 2667 0 Switch_To t16 -- 2668 16 Task_Semaphore_Wait_Complete sem:100b62ac -- * 2669 16 Simple_Entry_Call_Req t15 en:1 pc:00447c84 >Example - Verbose Mode
>set trace v on >set event 5 >tl Item Time Current task ---- ---- ------------ 2665 128.591202 Idle task Event => Interrupt_Exit 2 Address => 00438590 2666 128.591507 Idle task Event => Task_Semaphore_Signal Semaphore => 100b62ac 2667 128.591690 Idle task Event => Switch_To Task => <signal 2> (16) 2668 128.591797 <signal 2> (16) Event => Task_Semaphore_Wait_Complete Semaphore => 100b62ac * 2669 128.591995 <signal 2> (16) Event => Simple_Entry_Call_Req Task => end_it'1 (15) Entry => interrupt Caller => +signal_task_proc, (null), line 0 (00447c7c) >Example - Source Mode
>set event 5 >set trace s on >tl 2654 128.056503 output (2) Event => Select_Req Caller => output, path/phil.2.ada, line 129 (00436b44) 2656 128.056900 dining_room (3) Event => Simple_Accept_End Caller => dining_room, path/phil.2.ada, line 215 (00437a50) Task start address => 00437ffc 2657 128.057007 dining_room (3) Event => Select_Req Caller => dining_room, path/phil.2.ada, line 204 (004378c8) 2660 128.057404 philosopher (11) Event => Delay_Req Caller => philosopher, path/phil.2.ada, line 284 (0043844c) Time => 0.009000 secs * 2669 128.591995 <signal 2> (16) Event => Simple_Entry_Call_Req Task => end_it'1 (15) Entry => interrupt Caller => +signal_task_proc, (null), line 0 (00447c7c) >tm - trace move
Syntax
tmindex
Arguments
Description
Move to the event specified by index. Events are output with their index. If index is in the range of the current event buffer, it becomes the current event. The event is output in the current format.
>tm 20 Item Task Event Arg1 Arg2 Arg3 ---- ---- ----- ---- ---- ---- * 20 t1 Select_End en:3 ---- >tn - trace now
Syntax
tn
Description
Move to the current end (now) of the event buffer. Output this event in the current format.
>tn Item Task Event Arg1 Arg2 Arg3 ---- ---- ----- ---- ---- ---- * 2669 16 Simple_Entry_Call_Req t15 en:1 pc:00447c84 >to - trace output
Syntax
to [file_name
]
Arguments
Description
Trace output (to) dumps the event buffer to a file. The filename may be a simple identifier or a simple identifier with an extension (for example, myfile.log). If you wish to specify a full pathname, you must enclose it in quotes. (for example, "~/abc/myfile.log"). If you have previously dumped to a file, you may leave off the file name, but the file will be overwritten.
ts - trace start
Syntax
ts
Description
Move to the current start of the event buffer. Output this event in the current format.
>set trace v on >ts Item Time Current task ---- ---- ------------ * 0 7.262900 <main program> (1) Event => Simple_Entry_Call_Req Task => output (2) Entry => term_type_entry Caller => phil,path
/phil.2.ada, line 347 (004390a4) >tw - trace window
Syntax
tw
Description
Print events centered on the current event. The current event is marked by an asterisk.
The number of events displayed is controlled by the set event command. The default is 10.
>set event 5 >tw Item Time Current task ---- ---- ------------ 8 7.266400 output (2) Event => Select_End Entry => put 9 7.268400 output (2) Event => Simple_Accept_End Caller => output, path/phil.2.ada, line 155 (00436d18) Task start address => 0043695c * 10 7.268600 output (2) Event => Select_Req Caller => output, path/phil.2.ada, line 129 (00436b44) 11 7.268700 output (2) Event => Select_End Entry => put 12 7.271200 output (2) Event => Simple_Accept_End Caller => output, path/phil.2.ada, line 155 (00436d18) Task start address => 0043695c
Task Trace Visualizer —— apex_trace_driver and apex_xtraceThe Task trace visualizer consists of two tools, apex_trace_driver and apex_xtrace. apex_trace_driver can take one or more files of trace data and, from the program's load module and Ada libraries, interpret it into readable form.
The following topics are discussed in this section:
- Output Modes
- Requirements for use
- Command Line Interface
- Operation of apex_xtrace
- Main Window
- File
- View
- Options
- Help
Output Modes
apex_trace_driver has several modes of output
- It can output the trace file as readable text with most numerical fields interpreted in a source oriented form.
- It can analyze the trace file to output statistical information about the Ada tasking.
- It can communicate with apex_xtrace to allow the user to display tasking events graphically.
apex_xtrace can be driven either from the debugger, apex_debug, or from apex_trace_driver. In both cases its inputs are a text key file and a temporary trace file which may be a concatenation of more than 1 trace files. The temporary trace file may also have been restricted by time selection in apex_trace_driver.
Requirements for use
To use apex_trace_driver, you must link your program with an instrumented runtime. You must organize your program to start logging runtime events. Other options allow you to specify a file to which events are to be saved, to save the events at close-down, to specify your own event buffer, to specify your own time measurement routine on your own action routine when the buffer is full. These operations are described in more detail in the document section on using the Instrumented Runtime and in the worked example.
Command Line Interface
The command line interface can be obtained by entering
apex_trace_driver -h apex_trace_driver [-options
] [executable
[trace_file
..] ]
Filename or pathname of the program's load module.
The following options are available:
One or more trace file pathnames should be entered here.
apex_xtrace can be invoked directly, however it has no knowledge of Ada libraries so it has to be passed a key file. apex_trace_driver and apex_debug are both capable of driving apex_xtrace with key files.
apex_xtrace's command line interface is
apex_xtrace [-v][-iincrement
] [-pprecision
] [-t1time1
][-t2time2
] [-debugkey_file
] [trace_file
]When you drive apex_xtrace from apex_trace_driver or apex_debug, a script is written to a temporary file unit.replay.xxxxxx where unit is the name of the main Ada unit of the trace program. xxxxxx is a unique suffix generated by the mktemp() UNIX system service. You will find two more files, unit.key.xxxxxx and unit.trace.xxxxxx with the same or similar suffices. unit.key.xxxxxx is a text key file used to convert numerical information into source oriented text. The unit.trace.xxxxxx file is a processed trace file.
You can modify your replay or key files and run the replay file again. For example, you might want to restrict start and end times still further.
#!/bin/csh -f # Trace replay file for tasks0 apex_xtrace -v -t1 1.75 -t2 2.0 -i 1 -p 1000 -o tasks0.preset -debug tasks0.key.a0035Q tasks0.trace.a0035Q& If you reorder the task list in the key file, the graphical displays are reordered. The default is to order tasks by task sequence number.The other options to apex_xtrace are
Start in verbose mode. For internal use.
(increment) Specify the timer increment - the value of 1 bit in microseconds. [Default: 1]
(precision) Specify precision of timer in microseconds. [Default: 1000 (1 millisecond)]
If you start up apex_xtrace without setting the DISPLAY environment variable, it outputs a text interpretation of the trace data to standard output. For example, you could modify your replay file to
#!/bin/csh unsetenv DISPLAY apex_xtrace -v -t1 1.75 -t2 2.0 -debug tasks0.key.a09913 tasks0.trace.b09913 >tmp&
to capture a section of the trace data.
Operation of apex_xtrace
Whether you drive the apex_xtrace tool from the debugger, from apex_trace_driver operating on a saved file or using one of the replay scripts, the usage is the same.
Before starting, make sure your DISPLAY environment variable is set to an X window terminal to which you have access. For example,
setenv DISPLAY xx:0
where xx is the network name of your terminal.
The tool is implemented with Motif libraries and widgets. It need not run under the Motif Window Manager (mwm). For example, it runs quite adequately under OpenWindows. Keyboard traversal of menus may differ in small ways. For example, see the section on Help key usage in Help Files.
You should be familiar with operation of an X window terminal and terms such as select, drag, pulldown etc. Under Motif, the left mouse button is normally designated the Select button. Click the left button on a window and it is selected. The middle button is the Drag button. It is normally used for moving or copying items.
In apex_trace_driver, the left and right mouse buttons can be dragged on the graphical areas to select and zoom events respectively. Zoom defines a box which is to become a new graph boundary. You can zoom successively to get more detail in a graph. The Select button defines a box which restricts events of interest to the start and end time of the box and (sometimes) the start and end value on the vertical axis. Use of the Select button pops up a window of text events restricted by the selection. The middle (Drag) button can be used on the graphical areas to activate the crosshair (see Crosshair Display).
Menu items have an underlined letter. Once you have set keyboard focus on a window, you can type these underlined letters to traverse menus.
When you bring up a chart popup, the full range of time is displayed. This may look like chicken scratchings if your trace run is sufficiently long.
To zoom in for a more detailed view, put the cursor near the top at the start time of interest, press the right mouse button and drag towards the time axis at the end time of interest. A rectangle of dotted lines shows you your zoom selection. It will snap to a grid based on the current scale which might be slightly disorienting at first. When you release the button, the chart zooms. A button, Undo Zoom will show as sensitive so you can return to the previous display. You can zoom up to 10 times or until you reach the limit of timer resolution. If you try an 11th zoom in, you'll see a message similar to the following:
You must use the Undo button to cancel a zoom. Full Scale gets you back to the original chart.
If you do the same operation with the left (Select) mouse button, a raw text trace window is displayed, with events selected by the box you just drew.
Main Window
A typical main window is shown in Figure 2. The window consists of a Menu bar and a status area. The status area is updated automatically to reflect the trace data currently being analyzed. This date may change if apex_trace_driver was invoked from apex_debug and new information has been sent from apex_debug to apex_trace_driver.
Figure 2 apex_trace_driver Main Window
![]()
From this display, you have the following menu options. (Underlined letters are for keyboard control). Each of these options is discussed in detail.
File
File is used to select, close or print a file. The following operations are possible when you select File.
- Open...
- More Trace Data
- Close
- Open Dump File
- Close Dump File
- Exit
Open
Open is used to bring up a file selection box to allow you to select another trace file (Figure 3).
Figure 3 Trace Filename Selection
![]()
The box under Filter provides a mask of the files to be displayed in the file and directory lists. If you change the contents of the Filter box and select the Filter button, the directory and file lists are updated. To select a new directory, either type in a new directory pathname in the filter box and select the Filter button or highlight the desired entry in the Directories box.
More Trace Data
More trace data indicates your trace file is still being written and gets the rest of the data (used automatically under the debugger)
Close
Close closes the current file. If you use Open for a second time, Close is done automatically.
Open Dump File
Close Dump FileWhen apex_xtrace starts up, the default dump file assignment is to stdout. Each of the Charts that you can pop up from the View menu has a Dump button, Dumps range from the trace events as text, to the profiles used to generate the charts. If you do not want the dump to go to stdout, select a dump file for output using the File Selection Dialog popped up by selecting Open Dump File.
Strictly, the Close Dump File is not needed as opening a new file will close the old one.
Figure 4 Open Dump File
![]()
Print brings up a text window with 5 lines of shell commands. You can edit this text to match your requirements. If you then click Select window to print, the first line is interpreted. A cross cursor indicates xwd wants to know which window to dump. Move your cursor to the window to print and press the Select button. If you then click on Print, the postscript file is sent to the printer. Use man xwd or man xpr to find out more about these commands. Typical extra options to xpr are -height and -width. Figure 5 shows a print window.
Figure 5 Print Window
![]()
See Resources for task visualization for resources you can use to modify the script.
Exit
View
View enables you to view the trace data in a variety of manners. This includes task time lines, processes plotted against time, signals and waits, parallelism of activity, utilization, heap usage and the raw trace data. The following operations are possible when you select View.
- Tasks
- Processes
- Call Requests
- Signals/Waits
- Activity
- Heap Usage
- Raw Trace
Tasks
Tasks displays a task timeline chart. Tasks in execution are plotted vs. time. Figure 6 shows an example which has been zoomed. The scroll bars show the proportions displayed and their relative positions. The Undo last zoom button is not initially selectable. A zoom has been done in the figure below.
Figure 6 Task Timeline
![]()
Processes
Processes displays a process bargraph. Processes (sprocs or lightweight processes) are plotted vs. time. Figure 7 shows such a bargraph for a multithreaded runtime with 9 processes allocated.
The colors (or patterns on a monochrome display) correspond to those used on the Task Timeline display. Under Options > Display Organization, there is an option to color this and the task timeline by process.
Figure 7 Process Bargraph
![]()
Call Requests
Call Requests displays rendezvous calls and returns to the calling task. As shown in Figure 8, tasks are plotted against time and arrows are drawn from the caller to the called task. Broken line arrows mark the end of the rendezvous. If a call and return are not distinguishable at the time resolution, a double-ended arrow is drawn.
The button Show task timeline allows you to superimpose a monochromatic task timeline on this plot. You can see that there is usually a delay between a rendezvous request and the actual execution of the called task. Return events also usually occur long after the called task has suspended. The return arrow head marks the actual event logged.
Figure 8 Call Requests and Returns
![]()
Signals/Waits
Signals/Waits displays a signal/wait chart. Rendezvous are implemented by kernel signal and kernel wait in the multiprocessor runtime. The lines in this display show these connections as illustrated in Figure 9. Some connections may appear vertical due to the time scale. (Note that the single processor equivalent is not yet implemented).
The button, Show task timeline, allows you to superimpose a monochromatic task timeline on this plot.
Figure 9 Signals and Waits
![]()
Activity
Activity offers two options. Note that an active task is a task which is currently running. Parallelism shows tasks executing simultaneously. Figure 10 shows a run with a maximum parallelism of 10 but a more typical parallelism of 1 or 2.
Figure 10 Task Activity - Parallelism
![]()
Utilization is expressed as a histogram of the percentage of processes available. Figure 11 shows the same run zoomed.
Figure 11 Task Activity - Utilization
![]()
Heap Usage
Heap Usage displays the amount of heap allocated. Figure 12 shows a trace run with runaway heap usage. Heap Usage further discusses runaway heap usage.
Figure 12 Heap Usage
![]()
Raw Trace
Raw trace is actually interpreted as text. Two displays are available: Verbose and Concise. Figure 13 shows the verbose format.The dump button sends the text to stdout. If you intend to use dump, either start the tool with stdout directed to a file. For example,
apex_xtrace data >tmp&
or use the File > Open Dump File menu selection to open or create a file.
Figure 13 Raw Trace —— Verbose Format
![]()
Crosshair Display
A crosshair is available on the following displays: Tasks, Processes, Call requests, Activity, Signal/Wait, and Heap Usage. The crosshair can be activated by clicking on the middle mouse button while the cursor is positioned over the graphical area of one of the above displays.
Once activated a crosshair will appear on all the above displays. To deactivate the crosshair, use the Options > Remove Crosshair command.
On displays where the y-axis is in units of tasks or processes, the crosshair consists of a vertical and horizontal line with a circle around their intersection. Thus the crosshair pinpoints a specific time and a specific task or process. By default the crosshair first appears over the lowest task or process in the display.
On other displays (Activity and Heap Usage) the crosshair appears only as a vertical line, thus pinpointing only a specific time.
When the crosshair is activated, a text area appears towards the bottom of each of the displays. The first part of the text display is the crosshair location. For example:
"1.446667; my_pkg.my_task;"
indicates that the crosshair is placed over the task my_pkg in the package my_pkg, and that the crosshair is located at 1.446667 seconds along the x-axis. For Multiprocessor applications, the process is also indicated. For displays without a horizontal portion of the crosshair, the crosshair location includes only time.
After the crosshair location the "previous event" is listed. This is the event with the latest time up to and including the time of the crosshair. There are several constraints used to decide what event should be called the "previous event". First, the events must have been used to create the display. Second, if the crosshair has a horizontal portion, the events must have occurred on the task or process selected by the crosshair.
Finally, the time of the previous event is given.
Thus the full text area might look like
"1.446667; my_pkg.my_task; previous event: Switch_To @ 1.441300"
The crosshair and text can be updated either by clicking again on the middle mouse button, or by dragging the mouse across the display while depressing the middle button. All crosshairs are kept in sync along the x-axis (that is, with respect to time). Crosshairs in displays with like y-axis are also kept in sync (for example, Call requests and Tasks).
Figure 14 shows the Process Bargraph display with crosshair.
Figure 14 Crosshair Display
![]()
Options
Options is used to select parameters for the graphical displays. The following operations are possible when you select Options.
- Display Organization
- Time Selection
- Remove Crosshair
Display Organization
Display Organization causes the Organization dialog box to be displayed. Figure 15 shows this dialog box.
Figure 15 Display Organization
![]()
The Organization dialog has several components. At its top is a Color Palette. This is a group of squares each colored differently. These squares are drag sources. This means that you can press the middle (Drag) button over one of the squares and then drag the cursor to some location, taking information about the color with you.
Below the Color Palette are the task list and the process list.
- Change Colors
The way to change the color of a task, or process event type is to drag a color from the Organization dialog's Color Palette to the task list entry or process list entry label.
- Select Tasks and Processes
Initially, all tasks are selected. You can deselect a task by clicking the left (Select) button over an entry in the task list. The color box in the task list changes to a hollow box to indicate the task is now deselected. All graphs are immediately re-computed using only trace data collected from the selected tasks. To reselect a deselected task, just click on the task list entry again. You can select or deselect all the tasks at once via the Options menu.
Process selection and deselection works the same way.
- Select Coloring Mode
The coloring mode controls which set of colors (the task list or the process list) are used to draw the Task Timeline and the Process Bargraph. You can select the coloring mode via the Options menu.
- Save Organization State
It is possible to save the organization state in a preset file. This file stores information controlling color and visibility of tasks and processes in apex_xtrace.
The file is stored when the user selects the Save Organization State option from the Organization window's File pulldown menu.
By default, there is one preset file per program. When apex_trace_driver is invoked with the -x option, it names the preset file prog.preset, and enters the file name in the replay file created to invoke apex_xtrace. If the file exists, apex_xtrace uses it. However, the file is not actually created until the user saves the organization state in apex_xtrace. If the file does not exist, apex_xtrace is started with default colors and all tasks and processes selected. If you change the Organization state without saving the changes, you will be asked if you want to save the changes when you exit apex_trace_driver.
Time Selection
Time selection restricts the time range displayed. You can apply and remove this restriction. Typically it is removed when you do things like recolor tasks. Figure 16 shows the time selection box. You can perform time selection on the command line using the -t1 and -t2 options.
Figure 16 Time Selection
![]()
Remove Crosshair
Remove Crosshair causes the crosshair that is optionally displayed on the apex_xtrace graphs to be removed from the display. The crosshair is described in Crosshair Display.
Help
Help has been described in Help Files. It calls the Trace reference files in the Online Reference Manual.
Display Artifacts
Sometimes the graphs show one or more tasks apparently active while the process is at a breakpoint. These cases arise when tasks call the get time routine and are stopped before they log events. Finally, when the process is continued, they log the event with a low start time. This happens much more often in MP (threaded) runtimes since many tasks may be in contention for the lock on the event buffer.
If a task is resumed, then suspends so quickly that the two times logged are the same (low precision timer), the event is interpreted at draw time as a single pixel-wide rectangle. This has the disadvantage of never expanding as the graph is zoomed.
We sometimes lose events due to a lack of instrumentation points in the runtime. This problem will reduce in future releases. Right now, if we suddenly find that a task is executing on a process where another task was executing, we end the old task's execution profile and start the new task on that process. In order to reduce the inaccuracy, we use any event that does not represent a scheduling point as a reality check. If a task appeared to get suspended invisibly, then appears on another process doing a nonscheduling action (such as memory allocation), we start up a new execution profile at that point. The hope is that the time lines will improve in accuracy with experience, but be aware that a task timeline can overrun on a process, then appear on another process.
The runtime has implemented an optimization called the fast rendezvous. This allows part or all of a rendezvous to be executed in the calling task's context. Only if the called task makes a request that requires scheduling, does the context actually get switched. When apex_trace_driver analyzes trace data, it attempts to understand when this occurs. You will see text interpretations such as
0.062500 <main program> (1) on behalf of tasks.first_task (23) Event => Delay_Req Caller => tasks.first_task,path
/tasks.2.ada, line 104 (00439be8) Time => 0.000001where the main program called First_Task, but the context was not switched. Once the delay request has been made, a context switch is forced. The next event is
0.062600 <main program> (1) on behalf of tasks.first_task (23) Event => Switch_To_Rendezvous_In_Called Task => tasks.first_task (23) Task start address => tasks.first_task (004399f0)
0.062800 <main program> (1) Event => Switch_To Task => tasks.first_task (23)So that the main program is forced to switch to First_Task to implement the delay.
If a rendezvous executes without a context switch, apex_trace_driver does not detect its occurrence.
We are logging runtime scheduling points only. We know nothing about UNIX scheduling. If your machine is overloaded, you will see tasks apparently using up large chunks of time. They are probably being suspended by the UNIX scheduler for lack of resources (memory, access to files, time). This is not a problem on embedded systems. The problem is minimized on lightly loaded UNIX systems.
The default logging uses the Ada runtime's get_time support. On many UNIX systems, this can be gettimeofday(). If you have a fast microsecond timer, use the get_time callout facility. On SGI machines, you can modify the precision of the timer by a factor of 10 using the ftimer -f on command. (See man ftimer for information).
The visualization program is strongly dependent on runtime internals. We do not guarantee this tool will work completely with a mismatched version of the Apex Ada runtime.
ExampleThe following are covered in this section:
Running the Example
If you take the dining philosophers program from the examples directory as an example, you must first do several things to prepare for tracing.
- You must provide a clean exit to allow events to be logged to a file. The current form of the program only terminates by being killed.
- You must arrange to collect trace events and have them dumped to a file.
A source file, phil.2.ada, is supplied in rts_trace.ss. To adapt the program, import it into your working view and relink it with the -tracing runtime option.
Once you have linked, run it with the "collect trace data" button set or APEX_TRACE shell environment variable set.
The program will prompt you for your terminal type. If you are in an xterm window, respond for vt100.
When the program execution completes, a file LOG_FILE will exist in your current working view.
Now run the apex_trace_driver program. Either from the Tools > Trace menu, or from a shell command line
apex_trace_driver -x phil LOG_FILE
Note that you need to have your DISPLAY environment variable set to use the -x option.
Provided you have set APEX_TRACE, you will see a message that the trace file is being written.
Reading trace buffer ...
A file, LOG_FILE, should now exist in your directory.
Now run the apex_trace_driver program. If you are running on an X terminal you need to set up your DISPLAY environment variable.
On UNIX systems under the csh,
% setenv DISPLAYyour_X_terminal name
:0 % apex_trace_driver -x phil LOG_FILE
Note: If you do not have an X terminal, apex_trace_driver is capable of providing several text outputs.
% apex_trace_driver phil LOG_FILE >phil.trace
or to getting tasking statistics
% apex_trace_driver -s phil LOG_FILE >phil.stats
There are other options. Use apex_trace_driver -h to display them.
Examine the Trace File
On your X-terminal, a main window will appear, consisting of a menu bar and a status window, specifying some information about the data in the trace file.
Figure 17 apex_trace_driver Main Window
![]()
If you select the View menu, a pull down menu offers you several options.
- Tasks
- Processes
- Call requests
- Signals/Waits
- Activity
- Heap Usage
- Raw Trace
Drag the mouse cursor to the Tasks selection and let go of the button. The window shown in Figure 18 will appear. If it does not show all the tasks on the y-axis (the number of tasks is shown in the main window status), resize the window. The plot is of tasks executing versus time.
Figure 18 View Tasks
![]()
If you want to see more detail on the Task Timeline plot, put the mouse cursor at the top left of the plot, press the right mouse button and drag it to the bottom at the first tick from the origin. When you release the button, the graph should zoom in on the area of interest. The Undo last zoom button will become active so that you can undo your action, if you wish.
If you want to see what is going on in an area such as the far left of the plot, perform the same action using the left mouse button. This time a window will pop up showing the text interpretation of the events within the box you drew.
Now select the View > Call requests menu selection. This will bring up a window showing rendezvous activity (Figure 19). The plot is of a number of vertical arrows superimposed on a monochrome version of the task timeline chart. You will have to zoom to see some detail. Double ended arrows represent rendezvous which took place so quickly that the call and return registered the same time. Call requests are single arrows, and their corresponding end request event shows as a converse broken line arrow. This plot does not show when the requests were honored. It just says that the calling task made a request to the called so the head of the calling arrow is rarely in the called task's timeline plot. Similarly, the head of the broken line arrow shows when the calling task registers the end of the rendezvous, but the tail only shows which task was called, not when the call ended.
Figure 19 Call Requests
![]()
For more information on this subject, select the Help > On Context menu selection. Your cursor will change to a question mark. Move to the Call requests window and click the left (Select) mouse button. A help window will be displayed. Alternatively, click the left mouse button on the window and press the Help key on your keyboard.
Most of the other plots do not show a lot of interest with the philosophers program. It does not demonstrate much parallelism. The exception is the Heap Usage plot (Figure 20). It shows a slowly rising ramp of increasing heap usage. If you let the program run continuously, it will die with a Storage_Error after running for a time (a very long time).
Figure 20 Heap Usage
![]()
You can find out which task is doing the allocations by inspection (search for new in the source) or you can use the crosshair (see Crosshair Display). You can obtain more information by selecting the menu View > Raw Trace (Figure 21). This will allow you to identify the task doing all the Memory Allocate requests.
Figure 21 Raw Trace Output
![]()
You can also drive apex_xtrace from the debugger.
Do not forget to set the APEX_TRACE environment variable.
% apex_debug phil
Set a breakpoint in the main program at the statement that says "closing_down := true;" (line 308).
Run the program. Answer the question, let it run to the breakpoint.
>tl
You should see something like the following
Item Task Event Arg1 Arg2 Arg3 ---- ---- ----- ---- ---- ---- 1401 2 Switch_To t3 -- 1402 3 Simple_Accept_End pc:80205600 tsa:80205914 1403 3 Select_Req pc:802054a4 -- 1404 3 Switch_To t11 -- 1405 11 Simple_Entry_Call_End t2 tsa:80204974 1406 11 Delay_Req pc:80205c30 0.009000 s 1407 11 Switch_To_Idle_Task -- -- 1408 11 Switch_To t0(Idle) -- 1409 0 Switch_To t1 -- * 1410 1 Continue_From_Delay tsa:00000000 --You can browse around with debugger commands such as tb, tf, tm, ts, tn, or tw. To see verbose mode, enter
>set trace v
To restrict the number of events displayed at one time, enter
>set eventn
where n is the number of events required. For example,
>set event 2 >tl Item Time Current task ---- ---- ------------ 1409 10.100000 Idle task Event => Switch_To Task => <main program> (1) * 1410 10.100000 <main program> (1) Event => Continue_From_Delay Task start address => 00000000
(Task start addresses are logged for help in analysis - the main program does not store its start address).
You can also dump the current buffer to a file with the to command. For example,
>to abc Event buffer written to trace file abc
This will take a long time on cross systems. The method used by automatic trace on program completion is more efficient.
To start up apex_xtrace with the current event buffer as input, enter
>set trace x
then enter tl (or any of the other browse commands)
>tl apex_xtrace -debug phil.key.a004E6 phil.trace.a004E6& Item Time Current task ---- ---- ------------ 1409 10.100000 Idle task Event => Switch_To Task => <main program> (1) * 1410 10.100000 <main program> (1) Event => Continue_From_Delay Task start address => 00000000
Notice the line of output showing what was invoked. The two temporary files are created along with a third, phil.replay.a004E6, which contains the invocation line so you can replay apex_xtrace later if you wish. The file phil.key.a004E6 is a text file that provides conversions to apex_xtrace as this tool knows nothing of Apex or of load module symbols. The file phil.trace.a004E6 is a dump of the event buffer. If you run to another breakpoint and the event buffer has been updated, this file will be updated and apex_xtrace will modify its graphs.
You can close down apex_xtrace and apex_debug independently of each other.
Try selecting View > Raw Trace on the apex_trace_driver main window. A scrolled text window of verbosely interpreted trace data will be shown. You can switch to concise mode by clicking the mouse on the Verbose button. If you scroll forward on the raw trace window, you can find the events such as
7.000000 output (2) Event => Memory_Allocate Address => 802937e0 Size => 19 Caller => put'1, /vc/pc/cross/phil.2.ada, line 94 (80204348) 7.000000 output (2) Event => Memory_Allocate Address => 802937c0 Size => 19 Caller => put'1, /vc/pc/cross/phil.2.ada, line 95 (802043b8)In fact, all the Memory_Allocate events come from task output. There are no corresponding Memory_Deallocate events.
Heap Usage
If you scroll forward on the Raw Trace window, you will find the following event
1.995000 output (100830ec) Event => Memory_Allocate Address => 10081b70 Size => 19
In fact, all the Memory_Allocate events come from task output. There are no corresponding Memory_Deallocate events. This is the origin of the ramp seen in the Heap Usage display in Figure 12 .
If you go to the debugger and display the source of output (l 94), you will see several statements of the form
xs : as := new string'(integer'image(xp));
with no corresponding unchecked_deallocation
You could replace these statements with
xs: constant string := integer'image(xp);
and, hopefully, place the string on the stack rather than in the heap.
Strangely, enough, there is a statement
s := new string'( s( s'first .. s'first + elp - xp ) );
which effectively truncates the original string s to fit on the screen.
It would seem easier to change the put below to concatenate a slice of the original string.
if ( xp + s'length > elp ) then last_s := s'first + elp - xp ; end if; -- position and write string if term_type = '1' then text_io.put( ascii.esc & "[" & ys(2..ys'last) & ";" & xs(2..xs'last) & "H" & s(s'first..last_s)); else text_io.put( ascii.esc & "=" & character'val(32 + yp) & character'val(32 + xp) & s(s'first..last_s)); end if;
Examples of the modified philosophers program are supplied in the rts_trace.ss files phil.2.ada and phil2.2.ada as you can demonstrate using the apex_trace_driver tool.
Modified Philosophers Programs
Examples of the modified philosophers program are supplied in the example files phil.2.ada and phil2.2.ada. These files can be found in rts_trace.ss. These are listed in the next examples. The latter example (phil2.2.ada) does not use allocators.
- phil.2.ada example (Native systems only)
- phil.2.ada example (Embedded systems only)
- phil2.2.ada example (Native systems only)
- phil2.2.ada example (Embedded systems only)
phil.2.ada example (Native systems only)
-- UNIT: procedure PHL -- FILES: phil.2.ada -- COMPILE: ada phil.2.ada -M phil -o phil -- PURPOSE: tasking test and demonstration -- DESCRIPTION: The dining philosophers problem. -- Adapted to demonstrate task tracing. -- Usage: phil -- ...................................................................... -- with text_io; with system; -- TRACING --with unix; -- TRACING
procedure phil is
closing_down : boolean := false; -- TRACING closing_down_count : integer := 0; -- TRACING finished : boolean := false; -- TRACING
print_task_starts : constant boolean := true;
term_type: character := '1';
subtype seat is integer range 0..4;
task type output is entry put_cursor ( s : seat; at_table, eating : boolean); entry put_line(s: in string); entry put(s: in string); entry term_type_entry(x: in character); entry clear_screen; entry finish_output; -- TRACING end output;
o: output;
task type dining_room is entry allocate_seat (s : out seat); entry enter; entry leave; entry close; -- TRACING end dining_room;
dr: dining_room;
task type fork is entry pick_up; entry put_down; end fork;
cutlery : array (0..4) of fork;
task type philosopher;
school : array (0..4) of philosopher;
task rand_delay is entry rand; end rand_delay;
task body output is
term_type: character; -- '1' for vt100, '2' for f100 clear_sc : constant string := ascii.esc & '*' ; use text_io; pnum : character; r_s : seat; r_at_table, r_eating : boolean;
type xy_position is record x : integer range 0 .. 79; y : integer range 0 .. 23; end record;
eating_coords : array (seat) of xy_position := ( (28, 6), (25,12), (36,15), (46,12), (44, 6) );
thinking_coords : array(seat) of xy_position := ( (20,21), (30,21), (40,21), (50,21), (60,21) );
procedure put( item: in string ; pos: in xy_position ) is
xp : integer := pos.x; yp : integer := pos.y; elp : integer; type as is access string; s : as := new string'(item); xs : as := new string'(integer'image(xp)); ys : as := new string'(integer'image(yp));
begin if yp /= 23 then elp := 79; else elp := 78; end if; -- can't write 79,23
if ( xp + s'length > elp ) then s := new string'( s( s'first .. s'first + elp - xp ) ); end if;
-- position and write string if term_type = '1' then text_io.put( ascii.esc & "[" & ys(2..ys'last) & ";" & xs(2..xs'last) & "H" & s.all ); else text_io.put( ascii.esc & "=" & character'val(32 + yp) & character'val(32 + xp) & s.all ); end if; end put;
begin accept term_type_entry(x: in character) do term_type := x; end term_type_entry;
loop select accept put_cursor(s : seat; at_table, eating : boolean) do r_s := s; r_at_table := at_table; r_eating := eating;
pnum := character'val( r_s + 1 + character'pos('0') ); if r_at_table then put( " ", thinking_coords(r_s) ); if r_eating then put( "P" & pnum & "E", eating_coords(r_s) ); else put( "P" & pnum & " ", eating_coords(r_s) ); end if; else put( " ", eating_coords(r_s) ); put( "P" & pnum, thinking_coords(r_s) ); end if; end put_cursor; or accept put(s : in string) do text_io.put(s); end put; or accept put_line(s : in string) do text_io.put_line(s); end put_line; or accept clear_screen do if term_type = '1' then text_io.put(ascii.esc & "[2J" & ascii.esc & "[H"); else text_io.put(clear_sc); end if; delay 0.1; end clear_screen; or -- TRACING accept finish_output do -- TRACING null; -- TRACING end finish_output; -- TRACING end select; exit when finished; -- TRACING end loop; end output;
task body dining_room is
seats_filled : integer range 0..5 := 0; seat_allocation : seat := 0;
begin if print_task_starts then o.put_line("dining room starting"); end if;
o.clear_screen; o.put_line(" non_stop eating and thinking!"); o.put_line(" "); o.put_line(" "); o.put_line(" "); o.put_line(" ***"); o.put_line(" *******"); o.put_line(" ***********"); o.put_line(" ****** ******"); o.put_line(" ****** @@@ ******"); o.put_line(" ***** @@@@@ *****"); o.put_line(" ***** @@@ *****"); o.put_line(" ***** *****"); o.put_line(" *************"); o.put_line(" ***********"); o.put_line(" "); o.put_line(" ");
loop select --allocate fixed seat numbers to each of the five philosophers accept allocate_seat (s : out seat) do s := seat_allocation; if seat_allocation < 4 then seat_allocation := seat_allocation + 1; end if; end; or when seats_filled < 5 => accept enter do seats_filled := seats_filled + 1; end; or accept leave do seats_filled := seats_filled - 1; end; or accept close do -- TRACING null; -- TRACING end; -- TRACING end select; exit when finished; -- TRACING end loop; end dining_room;
task body fork is begin if print_task_starts then o.put_line("fork starting"); end if;
loop accept pick_up; accept put_down; exit when finished; -- TRACING end loop; end fork;
task body rand_delay is random : duration := 0.4; begin loop random := random + 0.05; if random > 0.7 then random := 0.4; end if; accept rand do delay random; end rand; exit when finished; -- TRACING end loop; end rand_delay;
task body philosopher is s : seat; begin if print_task_starts then o.put_line("philosopher starting"); end if;
dr.allocate_seat(s); --obtain seat on joining institution; dr.enter; o.put_cursor(s, at_table => true, eating => false); rand_delay.rand;
loop cutlery(s).pick_up; select cutlery((s+1) mod 5).pick_up; --obtained two forks; -- philosopher begins to eat o.put_cursor(s, at_table => true, eating => true); delay 1.0; cutlery((s+1) mod 5).put_down; cutlery(s).put_down;
--leave the room to think dr.leave; o.put_cursor(s, at_table => false, eating => false); delay 1.2;
-- enter dining room again dr.enter; o.put_cursor(s, at_table => true, eating => false); delay 0.9; or -- let someone else try for 2 forks delay 0.9; cutlery(s).put_down; rand_delay.rand; end select;
exit when closing_down; -- TRACING end loop; closing_down_count := closing_down_count+1; -- TRACING end philosopher;
task end_it is -- TRACING entry interrupt; -- TRACING for interrupt use at system.memory_address(2); -- SIGINT-- TRACING end end_it; -- TRACING
task body end_it is -- TRACING begin -- TRACING accept interrupt do -- TRACING text_io.put_line("Interrupt occurred"); -- TRACING end interrupt; -- TRACING
-- System dependent --text_io.put_line("Normal exit"); -- TRACING --unix.sys_exit(0); -- TRACING
-- More general method closing_down := true; -- TRACING while closing_down_count < school'last loop -- TRACING delay 0.1; -- TRACING end loop; -- TRACING finished := true; -- TRACING o.finish_output; -- TRACING rand_delay.rand; -- TRACING for i in cutlery'range loop -- TRACING cutlery(i).pick_up; -- TRACING cutlery(i).put_down; -- TRACING end loop; -- TRACING dr.close; -- TRACING text_io.put_line("Normal exit"); -- TRACING end end_it; -- TRACING
begin text_io.put("is this a vt100 (1) or an f100 (2) -->"); text_io.get(term_type); if term_type /= '1' and term_type /= '2' then text_io.put("that's not a 1 or a 2, i assume you have a vt100"); end if;
o.term_type_entry(term_type); end phil; -- ...................................................................... -- -- -- DISTRIBUTION AND COPYRIGHT: -- -- This software is released to the Public Domain (note: -- software released to the Public Domain is not subject -- to copyright protection). -- Restrictions on use or distribution: NONE -- -- DISCLAIMER: -- -- This software and its documentation are provided "AS IS" and -- without any expressed or implied warranties whatsoever. -- No warranties as to performance, merchantability, or fitness -- for a particular purpose exist. -- -- Because of the diversity of conditions and hardware under -- which this software may be used, no warranty of fitness for -- a particular purpose is offered. The user is advised to -- test the software thoroughly before relying on it. The user -- must assume the entire risk and liability of using this -- software. -- -- In no event shall any person or organization of people be -- held responsible for any direct, indirect, consequential -- or inconsequential damages or lost profits.
phil.2.ada example (Embedded systems only)
-- UNIT: procedure PHL -- FILES: phil.a -- COMPILE: ada phil.a -M phil -o phil -- PURPOSE: tasking test and demonstration -- DESCRIPTION: The dining philosophers problem. -- Adapted to demonstrate task tracing. -- Usage: phil -- .......................................................................... -- with Text_Io; procedure Phil is Closing_Down : Boolean := False; -- TRACING Closing_Down_Count : Integer := 0; -- TRACING Finished : Boolean := False; -- TRACING Print_Task_Starts : constant Boolean := True; Term_Type : Character := '1'; subtype Seat is Integer range 0 .. 4; task type Output is entry Put_Cursor (S : Seat; At_Table, Eating : Boolean); entry Put_Line (S : in String); entry Put (S : in String); entry Term_Type_Entry (X : in Character); entry Clear_Screen; entry Finish_Output; -- TRACING end Output; O : Output; task type Dining_Room is entry Allocate_Seat (S : out Seat); entry Enter; entry Leave; entry Close; -- TRACING end Dining_Room; Dr : Dining_Room; task type Fork is entry Pick_Up; entry Put_Down; end Fork; Cutlery : array (0 .. 4) of Fork; task type Philosopher; School : array (0 .. 4) of Philosopher; task Rand_Delay is entry Rand; end Rand_Delay; task body Output is Term_Type : Character; -- '1' for vt100, '2' for f100 Clear_Sc : constant String := Ascii.Esc & '*'; use Text_Io; Pnum : Character; R_S : Seat; R_At_Table, R_Eating : Boolean; type Xy_Position is record X : Integer range 0 .. 79; Y : Integer range 0 .. 23; end record; Eating_Coords : array (Seat) of Xy_Position := ((28, 6), (25, 12), (36, 15), (46, 12), (44, 6)); Thinking_Coords : array (Seat) of Xy_Position := ((20, 21), (30, 21), (40, 21), (50, 21), (60, 21)); procedure Put (Item : in String; Pos : in Xy_Position) is Xp : Integer := Pos.X; Yp : Integer := Pos.Y; Elp : Integer; type As is access String; S : As := new String'(Item); Xs : As := new String'(Integer'Image (Xp)); Ys : As := new String'(Integer'Image (Yp)); begin if Yp /= 23 then Elp := 79; else Elp := 78; end if; -- can't write 79,23 if (Xp + S'Length > Elp) then S := new String'(S (S'First .. S'First + Elp - Xp)); end if; -- position and write string if Term_Type = '1' then Text_Io.Put (Ascii.Esc & "[" & Ys (2 .. Ys'Last) & ";" & Xs (2 .. Xs'Last) & "H" & S.all); else Text_Io.Put (Ascii.Esc & "=" & Character'Val (32 + Yp) & Character'Val (32 + Xp) & S.all); end if; end Put; begin accept Term_Type_Entry (X : in Character) do Term_Type := X; end Term_Type_Entry; loop select accept Put_Cursor (S : Seat; At_Table, Eating : Boolean) do R_S := S; R_At_Table := At_Table; R_Eating := Eating; Pnum := Character'Val (R_S + 1 + Character'Pos ('0')); if R_At_Table then Put (" ", Thinking_Coords (R_S)); if R_Eating then Put ("P" & Pnum & "E", Eating_Coords (R_S)); else Put ("P" & Pnum & " ", Eating_Coords (R_S)); end if; else Put (" ", Eating_Coords (R_S)); Put ("P" & Pnum, Thinking_Coords (R_S)); end if; end Put_Cursor; or accept Put (S : in String) do Text_Io.Put (S); end Put; or accept Put_Line (S : in String) do Text_Io.Put_Line (S); end Put_Line; or accept Clear_Screen do if Term_Type = '1' then Text_Io.Put (Ascii.Esc & "[2J" & Ascii.Esc & "[H"); else Text_Io.Put (Clear_Sc); end if; delay 0.1; end Clear_Screen; or -- TRACING accept Finish_Output do -- TRACING null; -- TRACING end Finish_Output; -- TRACING end select; exit when Finished; -- TRACING end loop; end Output; task body Dining_Room is Seats_Filled : Integer range 0 .. 5 := 0; Seat_Allocation : Seat := 0; begin if Print_Task_Starts then O.Put_Line ("dining room starting"); end if; O.Clear_Screen; O.Put_Line (" non_stop eating and thinking!"); O.Put_Line (" "); O.Put_Line (" "); O.Put_Line (" "); O.Put_Line (" ***"); O.Put_Line (" *******"); O.Put_Line (" ***********"); O.Put_Line (" ****** ******"); O.Put_Line (" ****** @@@ ******"); O.Put_Line (" ***** @@@@@ *****"); O.Put_Line (" ***** @@@ *****"); O.Put_Line (" ***** *****"); O.Put_Line (" *************"); O.Put_Line (" ***********"); O.Put_Line (" "); O.Put_Line (" "); loop select --allocate fixed seat numbers to each of the five philosophers accept Allocate_Seat (S : out Seat) do S := Seat_Allocation; if Seat_Allocation < 4 then Seat_Allocation := Seat_Allocation + 1; end if; end Allocate_Seat; or when Seats_Filled < 5 => accept Enter do Seats_Filled := Seats_Filled + 1; end Enter; or accept Leave do Seats_Filled := Seats_Filled - 1; end Leave; or accept Close do -- TRACING null; -- TRACING end Close; -- TRACING end select; exit when Finished; -- TRACING end loop; end Dining_Room; task body Fork is begin if Print_Task_Starts then O.Put_Line ("fork starting"); end if; loop accept Pick_Up; accept Put_Down; exit when Finished; -- TRACING end loop; end Fork; task body Rand_Delay is Random : Duration := 0.4;
begin loop Random := Random + 0.05; if Random > 0.7 then Random := 0.4; end if; accept Rand do delay Random; end Rand; exit when Finished; -- TRACING end loop; end Rand_Delay; task body Philosopher is S : Seat; begin if Print_Task_Starts then O.Put_Line ("philosopher starting"); end if; Dr.Allocate_Seat (S); --obtain seat on joining institution; Dr.Enter; O.Put_Cursor (S, At_Table => True, Eating => False); Rand_Delay.Rand; loop Cutlery (S).Pick_Up; select Cutlery ((S + 1) mod 5).Pick_Up; --obtained two forks; -- philosopher begins to eat O.Put_Cursor (S, At_Table => True, Eating => True); delay 1.0; Cutlery ((S + 1) mod 5).Put_Down; Cutlery (S).Put_Down; --leave the room to think Dr.Leave; O.Put_Cursor (S, At_Table => False, Eating => False); delay 1.2; -- enter dining room again Dr.Enter; O.Put_Cursor (S, At_Table => True, Eating => False); delay 0.9; or -- let someone else try for 2 forks delay 0.9; Cutlery (S).Put_Down; Rand_Delay.Rand; end select; exit when Closing_Down; -- TRACING end loop; Closing_Down_Count := Closing_Down_Count + 1; -- TRACING end Philosopher; begin Text_Io.Put ("is this a vt100 (1) or an f100 (2) -->"); Text_Io.Get (Term_Type); if Term_Type /= '1' and Term_Type /= '2' then Text_Io.Put ("that's not a 1 or a 2, i'll assume you have a vt100"); end if; O.Term_Type_Entry (Term_Type); delay 10.0; Closing_Down := True; -- TRACING while Closing_Down_Count <= School'Last loop -- TRACING delay 0.1; -- TRACING end loop; -- TRACING Finished := True; -- TRACING O.Finish_Output; -- TRACING Rand_Delay.Rand; -- TRACING for I in Cutlery'Range loop -- TRACING Cutlery (I).Pick_Up; -- TRACING Cutlery (I).Put_Down; -- TRACING end loop; -- TRACING Dr.Close; -- TRACING end Phil; -- .......................................................................... -- -- -- DISTRIBUTION AND COPYRIGHT: -- -- This software is released to the Public Domain (note: -- software released to the Public Domain is not subject -- to copyright protection). -- Restrictions on use or distribution: NONE -- -- DISCLAIMER: -- -- This software and its documentation are provided "AS IS" and -- without any expressed or implied warranties whatsoever. -- No warranties as to performance, merchantability, or fitness -- for a particular purpose exist. -- -- Because of the diversity of conditions and hardware under -- which this software may be used, no warranty of fitness for -- a particular purpose is offered. The user is advised to -- test the software thoroughly before relying on it. The user -- must assume the entire risk and liability of using this -- software. -- -- In no event shall any person or organization of people be -- held responsible for any direct, indirect, consequential -- or inconsequential damages or lost profits.phil2.2.ada example (Native systems only)
-- UNIT: procedure PHIL2 -- FILES: phil2.2.ada -- COMPILE: ada phil2.2.ada -M phil2 -o phil2 -- PURPOSE: tasking test and demonstration -- DESCRIPTION: The dining philosophers problem. -- Adapted to demonstrate tracing. Memory leak fixed. -- Usage: phil2 -- ...................................................................... -- with text_io; with system; -- TRACING --with unix; -- TRACING
procedure phil2 is
closing_down : boolean := false; -- TRACING closing_down_count : integer := 0; -- TRACING finished : boolean := false; -- TRACING
print_task_starts : constant boolean := true;
term_type: character := '1';
subtype seat is integer range 0..4;
task type output is entry put_cursor ( s : seat; at_table, eating : boolean); entry put_line(s: in string); entry put(s: in string); entry term_type_entry(x: in character); entry clear_screen; entry finish_output; -- TRACING end output;
o: output;
task type dining_room is entry allocate_seat (s : out seat); entry enter; entry leave; entry close; -- TRACING end dining_room;
dr: dining_room;
task type fork is entry pick_up; entry put_down; end fork;
cutlery : array (0..4) of fork;
task type philosopher;
school : array (0..4) of philosopher;
task rand_delay is entry rand; end rand_delay;
task body output is
term_type: character; -- '1' for vt100, '2' for f100 clear_sc : constant string := ascii.esc & '*' ; use text_io; pnum : character; r_s : seat; r_at_table, r_eating : boolean;
type xy_position is record x : integer range 0 .. 79; y : integer range 0 .. 23; end record;
eating_coords : array (seat) of xy_position := ( (28, 6), (25,12), (36,15), (46,12), (44, 6) );
thinking_coords : array(seat) of xy_position := ( (20,21), (30,21), (40,21), (50,21), (60,21) );
procedure put( item: in string ; pos: in xy_position ) is
xp : integer := pos.x; yp : integer := pos.y; elp : integer; s : constant string := item; last_s : integer := s'last; xs : constant string := integer'image(xp); ys : constant string := integer'image(yp);
begin if yp /= 23 then elp := 79; else elp := 78; end if; -- can't write 79,23
if ( xp + s'length > elp ) then last_s := s'first + elp - xp ; end if;
-- position and write string if term_type = '1' then text_io.put( ascii.esc & "[" & ys(2..ys'last) & ";" & xs(2..xs'last) & "H" & s(s'first..last_s)); else text_io.put( ascii.esc & "=" & character'val(32 + yp) & character'val(32 + xp) & s(s'first..last_s)); end if; end put;
begin accept term_type_entry(x: in character) do term_type := x; end term_type_entry;
loop select accept put_cursor(s : seat; at_table, eating : boolean) do r_s := s; r_at_table := at_table; r_eating := eating;
pnum := character'val( r_s + 1 + character'pos('0') ); if r_at_table then put( " ", thinking_coords(r_s) ); if r_eating then put( "P" & pnum & "E", eating_coords(r_s) ); else put( "P" & pnum & " ", eating_coords(r_s) ); end if; else put( " ", eating_coords(r_s) ); put( "P" & pnum, thinking_coords(r_s) ); end if; end put_cursor; or accept put(s : in string) do text_io.put(s); end put; or accept put_line(s : in string) do text_io.put_line(s); end put_line; or accept clear_screen do if term_type = '1' then text_io.put(ascii.esc & "[2J" & ascii.esc & "[H"); else text_io.put(clear_sc); end if; delay 0.1; end clear_screen; or -- TRACING accept finish_output do -- TRACING null; -- TRACING end finish_output; -- TRACING end select; exit when finished; -- TRACING end loop; end output;
task body dining_room is
seats_filled : integer range 0..5 := 0; seat_allocation : seat := 0;
begin if print_task_starts then o.put_line("dining room starting"); end if;
o.clear_screen; o.put_line(" non_stop eating and thinking!"); o.put_line(" "); o.put_line(" "); o.put_line(" "); o.put_line(" ***"); o.put_line(" *******"); o.put_line(" ***********"); o.put_line(" ****** ******"); o.put_line(" ****** @@@ ******"); o.put_line(" ***** @@@@@ *****"); o.put_line(" ***** @@@ *****"); o.put_line(" ***** *****"); o.put_line(" *************"); o.put_line(" ***********"); o.put_line(" "); o.put_line(" ");
loop select --allocate fixed seat numbers to each of the five philosophers accept allocate_seat (s : out seat) do s := seat_allocation; if seat_allocation < 4 then seat_allocation := seat_allocation + 1; end if; end; or when seats_filled < 5 => accept enter do seats_filled := seats_filled + 1; end; or accept leave do seats_filled := seats_filled - 1; end; or accept close do -- TRACING null; -- TRACING end; -- TRACING end select; exit when finished; -- TRACING end loop; end dining_room;
task body fork is begin if print_task_starts then o.put_line("fork starting"); end if;
loop accept pick_up; accept put_down; exit when finished; -- TRACING end loop; end fork;
task body rand_delay is random : duration := 0.4; begin loop random := random + 0.05; if random > 0.7 then random := 0.4; end if; accept rand do delay random; end rand; exit when finished; -- TRACING end loop; end rand_delay;
task body philosopher is s : seat; begin if print_task_starts then o.put_line("philosopher starting"); end if;
dr.allocate_seat(s); --obtain seat on joining institution; dr.enter; o.put_cursor(s, at_table => true, eating => false); rand_delay.rand;
loop cutlery(s).pick_up; select cutlery((s+1) mod 5).pick_up; --obtained two forks; -- philosopher begins to eat o.put_cursor(s, at_table => true, eating => true); delay 1.0; cutlery((s+1) mod 5).put_down; cutlery(s).put_down;
--leave the room to think dr.leave; o.put_cursor(s, at_table => false, eating => false); delay 1.2;
-- enter dining room again dr.enter; o.put_cursor(s, at_table => true, eating => false); delay 0.9; or -- let someone else try for 2 forks delay 0.9; cutlery(s).put_down; rand_delay.rand; end select;
exit when closing_down; -- TRACING end loop; closing_down_count := closing_down_count+1; -- TRACING end philosopher;
task end_it is -- TRACING entry interrupt; -- TRACING for interrupt use at system.memory_address(2); -- SIGINT -- TRACING end end_it; -- TRACING
task body end_it is -- TRACING begin -- TRACING accept interrupt do -- TRACING text_io.put_line("Interrupt occurred"); -- TRACING end interrupt; -- TRACING -- System dependent exit --text_io.put_line("Normal exit"); -- TRACING --unix.sys_exit(0); -- TRACING
-- More general exit closing_down := true; -- TRACING while closing_down_count < school'last loop -- TRACING delay 0.1; -- TRACING end loop; -- TRACING finished := true; -- TRACING o.finish_output; -- TRACING rand_delay.rand; -- TRACING for i in cutlery'range loop -- TRACING cutlery(i).pick_up; -- TRACING cutlery(i).put_down; -- TRACING end loop; -- TRACING dr.close; -- TRACING text_io.put_line("Normal exit"); -- TRACING end end_it; -- TRACING
begin text_io.put("is this a vt100 (1) or an f100 (2) -->"); text_io.get(term_type); if term_type /= '1' and term_type /= '2' then text_io.put("that's not a 1 or a 2, i assume you have a vt100"); end if;
o.term_type_entry(term_type); end phil2; -- .......................................................................... -- -- -- DISTRIBUTION AND COPYRIGHT: -- -- This software is released to the Public Domain (note: -- software released to the Public Domain is not subject -- to copyright protection). -- Restrictions on use or distribution: NONE -- -- DISCLAIMER: -- -- This software and its documentation are provided "AS IS" and -- without any expressed or implied warranties whatsoever. -- No warranties as to performance, merchantability, or fitness -- for a particular purpose exist. -- -- Because of the diversity of conditions and hardware under -- which this software may be used, no warranty of fitness for -- a particular purpose is offered. The user is advised to -- test the software thoroughly before relying on it. The user -- must assume the entire risk and liability of using this -- software. -- -- In no event shall any person or organization of people be -- held responsible for any direct, indirect, consequential -- or inconsequential damages or lost profits.phil2.2.ada example (Embedded systems only)
-- UNIT: procedure PHIL2 -- FILES: phil2.a -- COMPILE: ada phil2.a -M phil2 -o phil2 -- PURPOSE: tasking test and demonstration -- DESCRIPTION: The dining philosophers problem. -- Adapted to demonstrate tracing. Memory leak fixed. -- Usage: phil2 -- .......................................................................... -- with Text_Io; procedure Phil2 is Closing_Down : Boolean := False; -- TRACING Closing_Down_Count : Integer := 0; -- TRACING Finished : Boolean := False; -- TRACING Print_Task_Starts : constant Boolean := True; Term_Type : Character := '1'; subtype Seat is Integer range 0 .. 4; task type Output is entry Put_Cursor (S : Seat; At_Table, Eating : Boolean); entry Put_Line (S : in String); entry Put (S : in String); entry Term_Type_Entry (X : in Character); entry Clear_Screen; entry Finish_Output; -- TRACING end Output; O : Output; task type Dining_Room is entry Allocate_Seat (S : out Seat); entry Enter; entry Leave; entry Close; -- TRACING end Dining_Room; Dr : Dining_Room; task type Fork is entry Pick_Up; entry Put_Down; end Fork; Cutlery : array (0 .. 4) of Fork; task type Philosopher; School : array (0 .. 4) of Philosopher; task Rand_Delay is entry Rand; end Rand_Delay; task body Output is Term_Type : Character; -- '1' for vt100, '2' for f100 Clear_Sc : constant String := Ascii.Esc & '*'; use Text_Io; Pnum : Character; R_S : Seat; R_At_Table, R_Eating : Boolean; type Xy_Position is record X : Integer range 0 .. 79; Y : Integer range 0 .. 23; end record; Eating_Coords : array (Seat) of Xy_Position := ((28, 6), (25, 12), (36, 15), (46, 12), (44, 6)); Thinking_Coords : array (Seat) of Xy_Position := ((20, 21), (30, 21), (40, 21), (50, 21), (60, 21)); procedure Put (Item : in String; Pos : in Xy_Position) is Xp : Integer := Pos.X; Yp : Integer := Pos.Y; Elp : Integer; S : constant String := Item; Last_S : Integer := S'Last; Xs : constant String := Integer'Image (Xp); Ys : constant String := Integer'Image (Yp); begin if Yp /= 23 then Elp := 79; else Elp := 78; end if; -- can't write 79,23 if (Xp + S'Length > Elp) then Last_S := S'First + Elp - Xp; end if; -- position and write string if Term_Type = '1' then Text_Io.Put (Ascii.Esc & "[" & Ys (2 .. Ys'Last) & ";" & Xs (2 .. Xs'Last) & "H" & S (S'First .. Last_S)); else Text_Io.Put (Ascii.Esc & "=" & Character'Val (32 + Yp) & Character'Val (32 + Xp) & S (S'First .. Last_S)); end if; end Put; begin accept Term_Type_Entry (X : in Character) do Term_Type := X; end Term_Type_Entry; loop select accept Put_Cursor (S : Seat; At_Table, Eating : Boolean) do R_S := S; R_At_Table := At_Table; R_Eating := Eating; Pnum := Character'Val (R_S + 1 + Character'Pos ('0')); if R_At_Table then Put (" ", Thinking_Coords (R_S)); if R_Eating then Put ("P" & Pnum & "E", Eating_Coords (R_S)); else Put ("P" & Pnum & " ", Eating_Coords (R_S)); end if; else Put (" ", Eating_Coords (R_S)); Put ("P" & Pnum, Thinking_Coords (R_S)); end if; end Put_Cursor; or accept Put (S : in String) do Text_Io.Put (S); end Put; or accept Put_Line (S : in String) do Text_Io.Put_Line (S); end Put_Line; or accept Clear_Screen do if Term_Type = '1' then Text_Io.Put (Ascii.Esc & "[2J" & Ascii.Esc & "[H"); else Text_Io.Put (Clear_Sc); end if; delay 0.1; end Clear_Screen; or -- TRACING accept Finish_Output do -- TRACING null; -- TRACING end Finish_Output; -- TRACING end select; exit when Finished; -- TRACING end loop; end Output; task body Dining_Room is Seats_Filled : Integer range 0 .. 5 := 0; Seat_Allocation : Seat := 0; begin if Print_Task_Starts then O.Put_Line ("dining room starting"); end if; O.Clear_Screen; O.Put_Line (" non_stop eating and thinking!"); O.Put_Line (" "); O.Put_Line (" "); O.Put_Line (" ");
O.Put_Line (" ***"); O.Put_Line (" *******"); O.Put_Line (" ***********"); O.Put_Line (" ****** ******"); O.Put_Line (" ****** @@@ ******"); O.Put_Line (" ***** @@@@@ *****"); O.Put_Line (" ***** @@@ *****"); O.Put_Line (" ***** *****"); O.Put_Line (" *************"); O.Put_Line (" ***********"); O.Put_Line (" "); O.Put_Line (" "); loop select --allocate fixed seat numbers to each of the five philosophers accept Allocate_Seat (S : out Seat) do S := Seat_Allocation; if Seat_Allocation < 4 then Seat_Allocation := Seat_Allocation + 1; end if; end Allocate_Seat; or when Seats_Filled < 5 => accept Enter do Seats_Filled := Seats_Filled + 1; end Enter; or accept Leave do Seats_Filled := Seats_Filled - 1; end Leave; or accept Close do -- TRACING null; -- TRACING end Close; -- TRACING end select; exit when Finished; -- TRACING end loop; end Dining_Room; task body Fork is begin if Print_Task_Starts then O.Put_Line ("fork starting"); end if; loop accept Pick_Up; accept Put_Down; exit when Finished; -- TRACING end loop; end Fork; task body Rand_Delay is Random : Duration := 0.4; begin loop Random := Random + 0.05; if Random > 0.7 then Random := 0.4; end if; accept Rand do delay Random; end Rand; exit when Finished; -- TRACING end loop; end Rand_Delay; task body Philosopher is S : Seat; begin if Print_Task_Starts then O.Put_Line ("philosopher starting"); end if; Dr.Allocate_Seat (S); --obtain seat on joining institution; Dr.Enter; O.Put_Cursor (S, At_Table => True, Eating => False); Rand_Delay.Rand; loop Cutlery (S).Pick_Up; select Cutlery ((S + 1) mod 5).Pick_Up; --obtained two forks; -- philosopher begins to eat O.Put_Cursor (S, At_Table => True, Eating => True); delay 1.0; Cutlery ((S + 1) mod 5).Put_Down; Cutlery (S).Put_Down; --leave the room to think Dr.Leave; O.Put_Cursor (S, At_Table => False, Eating => False); delay 1.2; -- enter dining room again Dr.Enter; O.Put_Cursor (S, At_Table => True, Eating => False); delay 0.9; or -- let someone else try for 2 forks delay 0.9; Cutlery (S).Put_Down; Rand_Delay.Rand; end select; exit when Closing_Down; -- TRACING end loop; Closing_Down_Count := Closing_Down_Count + 1; -- TRACING end Philosopher; begin Text_Io.Put ("is this a vt100 (1) or an f100 (2) -->"); Text_Io.Get (Term_Type); if Term_Type /= '1' and Term_Type /= '2' then Text_Io.Put ("that's not a 1 or a 2, i'll assume you have a vt100"); end if; O.Term_Type_Entry (Term_Type); -- TRACING delay 10.0; -- TRACING Closing_Down := True; -- TRACING while Closing_Down_Count <= School'Last loop -- TRACING delay 0.1; -- TRACING end loop; -- TRACING Finished := True; -- TRACING O.Finish_Output; -- TRACING Rand_Delay.Rand; -- TRACING for I in Cutlery'Range loop -- TRACING Cutlery (I).Pick_Up; -- TRACING Cutlery (I).Put_Down; -- TRACING end loop; -- TRACING Dr.Close; -- TRACING end Phil2; -- .......................................................................... -- -- -- DISTRIBUTION AND COPYRIGHT:
-- -- This software is released to the Public Domain (note: -- software released to the Public Domain is not subject -- to copyright protection). -- Restrictions on use or distribution: NONE -- -- DISCLAIMER: -- -- This software and its documentation are provided "AS IS" and -- without any expressed or implied warranties whatsoever. -- No warranties as to performance, merchantability, or fitness -- for a particular purpose exist. -- -- Because of the diversity of conditions and hardware under -- which this software may be used, no warranty of fitness for -- a particular purpose is offered. The user is advised to -- test the software thoroughly before relying on it. The user -- must assume the entire risk and liability of using this -- software. -- -- In no event shall any person or organization of people be -- held responsible for any direct, indirect, consequential -- or inconsequential damages or lost profits.
Rational Software Corporation http://www.rational.com support@rational.com techpubs@rational.com Copyright © 1993-2002, Rational Software Corporation. All rights reserved. |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |