007 4746 014
User Manual: 007-4746-014
Open the PDF directly: View PDF .
Page Count: 212
Download | |
Open PDF In Browser | View PDF |
REACT Real-Time for Linux® Programmer’s Guide TM 007–4746–014 COPYRIGHT © 2005–2008, 2010 SGI. All rights reserved; provided portions may be copyright in third parties, as indicated elsewhere herein. No permission is granted to copy, distribute, or create derivative works from the contents of this electronic documentation in any manner, in whole or in part, without the prior written permission of SGI. LIMITED RIGHTS LEGEND The software described in this document is "commercial computer software" provided with restricted rights (except as to included open/free source) as specified in the FAR 52.227-19 and/or the DFAR 227.7202, or successive sections. Use beyond license provisions is a violation of worldwide intellectual property laws, treaties and conventions. This document is provided with limited rights as defined in 52.227-14. TRADEMARKS AND ATTRIBUTIONS Altix, REACT, SGI, the SGI cube, and the SGI logo are trademarks or registered trademarks of Silicon Graphics International Corp. or its subsidiaries in the United States and other countries. IBM is a registered trademark of IBM Corporation. Intel is a registered trademark of Intel Corporation or its subsidiaries in the United States and other countries. Linux is a registered trademark of Linus Torvalds in several countries. LSI Logic is a registered trademark of LSI Corporation. Novell and SUSE are registered trademarks of Novell, Inc. in the United States and other countries. Red Hat and all Red Hat-based trademarks are trademarks or registered trademarks of Red Hat, Inc. in the United States and other countries. All other trademarks mentioned herein are the property of their respective owners. New Features in this Guide This revision contains the following: • Support for SGI® REACTTM 1.0 (a new separate release, and a member of the SGI Performance Suite) • Support for running REACT on third-party x86–64 systems. For best performance, run REACT on SGI x86-64 servers. See "REACT Requirements" on page 7. • Support for the SGI Linux® Trace (SLT) user library C application programming interface (API) to generate SLT user events. See Chapter 12, "Using the SGI Linux Trace User Library" on page 139. • Support for the following new API routines to change the CPU affinity of the given IRQs and change permissions so that non-root users can run REACT: – "cpu_sysrt_irq" on page 121 – "cpu_sysrt_perm" on page 122 • Information about the deprecated reactconf.pl command has been removed because it has been superseded by the react command. 007–4746–014 iii Record of Revision 007–4746–014 Version Description 001 February 2005 Original publication to support REACT real-time for Linux 4.0 002 July 2005 Revision to support REACT real-time for Linux 4.2 003 December 2005 Revision to support REACT real-time for Linux 4.3 004 July 2006 Revision to support REACT real-time for Linux 5.0 005 February 2007 Revision to support REACT real-time for Linux 5.1 006 June 2007 Revision to support REACT real-time for Linux 5.2 007 September 2007 Revision to support REACT real-time for Linux 5.3 008 December 2007 Revision to support REACT real-time for Linux 5.4 009 March 2008 Revision to support REACT real-time for Linux 5.5 010 June 2008 Revision to support REACT real-time for Linux 6.0 011 September 2008 Revision to support REACT real-time for Linux 6.1 012 January 2010 Revision to support REACT real-time for Linux 7.0 v Record of Revision vi 013 May 2010 Revision to support REACT real-time for Linux 7.1 (part of the SGI ProPack 7.1 release) 014 October 2010 Revision to support SGI REACT 1.0 (a new separate release, and a member of the SGI Performance Suite) 007–4746–014 Contents About This Guide Audience . . . . . . . . . . What This Guide Contains . . . . . . . . . . . . . . . xxiii . . . . . . . . . . . . . . . . . . . . xxiii . . . . . . . . . . . . . . . . . . . . xxiii . . . . . . . . . . . . . . . . . . . Related Publications and Sites Conventions . . . . xxv . . . . . . . . . . . . . . . . . . . . . . . xxvi Obtaining Publications . . . . . . . . . . . . . . . . . . . . . . xxvi Reader Comments . . . . . . . . . . . . . . . . . . . . . . xxvii . 1. Introduction . Real-Time Programs . . . . . . . . . . . . . . . . . . . . . . 1 . . . . . . . . . . . . . . . . . . . . . 1 . . . . . . . . . . . . . . . . . . . . . 2 . . . . . . . . . . . . . . . . . . . 2 . . . . . . . . . . . . . . . . . . . . 3 Ground Vehicle Simulators . . . . . . . . . . . . . . . . . . . 3 Plant Control Simulators . . . . . . . . . . . . . . . . . . . 3 Virtual Reality Simulators . . . . . . . . . . . . . . . . . . . 4 Hardware-in-the-Loop Simulators . . . . . . . . . . . . . . . . . 4 Control Law Processor Stimulator . . . . . . . . . . . . . . . . . 4 Wave Tank Stimulator . . . . . . . . . . . . . . . . . . . . 5 Data Collection Systems . . . . . . . . . . . . . . . . . . . . 5 Process Control Systems . . . . . . . . . . . . . . . . . . . . 6 Real-Time Applications Simulators and Stimulators Aircraft Simulators REACTTM Features . REACT Requirements REACT RPMs . . . . . . . . . . . . . . . . . . . . . . . . . 6 . . . . . . . . . . . . . . . . . . . . . . 7 . . . . . . . . . . . . . . . . . . . . . . 7 . . 9 2. Linux and REACT Support for Real–Time Programs 007–4746–014 . . . . . vii Contents Kernel Facilities . . . . . . Special Scheduling Disciplines Virtual Memory Locking . . . . . . . . . . . . . . . . . . 9 . . . . . . . . . . . . . . . . . . 9 . . . . . . . . . . . . . . . . . . . . 10 Processes Mapping and CPUs . . . . . . . . . . . . . . . . . . . 10 Interrupt Distribution Control . . . . . . . . . . . . . . . . . . . 11 . . . . . . . . . . . . . . . . . . . 11 . . . . . . . . . . . . 12 Frame Scheduler Clocks and Timers Clocks . . . . (Altix® . . Direct RTC Access . . UV 1000 and Altix UV 100) . . . . . . . . . . . . . . . . . . . . . . 12 . . . . . . . . . . . . . . . . . . . . . . 14 . . . . . . . . . . . . . . . . . . . . 14 . . . . . . . . . . . . . . . . . . . . 14 . . . . . . . . . . . . . . . . . . 15 . . . . . . 17 Interchassis Communication Socket Programming . Message-Passing Interface (MPI) 3. External Interrupts Abstraction Layer . . sysfs Attribute Files . . . . . . . . . . . . . . . . . . . . . . 17 . . . . . . . . . . . . . . . . . . . . . 18 . . . . . . . . . . . . . . . . . . . 20 . . . . . . . . . . . . . . . . . . . . 20 . . . . . . . . . . . . . . . . . . . . 20 . . . . . . . . . . . . . . . . . 20 . Exclusively Accessing a Device Low-Level Driver Interface . . Implementation Functions . . . . . . . . . . . . . . . . . . . 23 . . . . . . . . . . . . . . . . . . . 24 . . . . . . . . . . . . . . . . . . . 24 . . . . . . . . . . . . . . . . 28 When an External Interrupt Occurs Driver Deregistration . . Interrupt Notification Interface viii . . . . . Waiting for Interrupts Driver Registration . . . . The /dev/extint# Device Counting Interrupts . . . . . . . . . . . . . . . . . . . . . . 28 . . . . . . . . . . . . . . . . . . 28 Callout Mechanism . . . . . . . . . . . . . . . . . . . . . 29 Callout Registration . . . . . . . . . . . . . . . . . . . . . 29 007–4746–014 REACT Callout Deregistration . . . . . . . . TM . . Making Use of Unsupported Hardware Device Capabilities Low-level Driver Template . Real-Time for Linux® Programmer’s Guide . . . . . . . . . . 30 . . . . . . . . . . 31 . . . . . . . . . . . . . . . . . . . 31 . . . . . . . . . . . . . . . . . . . 32 Multiple Independent Drivers . . . . . . . . . . . . . . . . . . . 32 External Interrupt Output . . . . . . . . . . . . . . . . . . . . 34 External Interrupt Ingest . . . . . . . . . . . . . . . . . . . . 36 . . . . . . . . . . . . . . . . . . . . 36 . . . . . . 39 Example: SGI IOC4 PCI Device Physical Interfaces . 4. CPU Workload . . . . . . . . . Using Priorities and Scheduling Queues Scheduling Concepts . . . . . . . . . . . . . . . . . . . . . . . 39 . . . . . . . . . . . . . . . . . . . . . 39 . . . . . . . . . . . . . . . . . . . . . 40 Real-Time Priority Band . . . . . . . . . . . . . . . . . . . . 40 . . . . . . . . . . . . . . . . . . . . 41 . . . . . . . . . . . . . . . . 42 . . . . . . . . . . . . . . . . . 43 . . . . . . . . . . . . . . . . . 43 . . . . . . . . . . . . . . . . . 43 . . . . . . . . . . . . . . . . . 44 Restricting a CPU from Scheduled Work and Isolating it from Scheduler Load Balancing 45 Shielding a CPU from Timer Interrupts Timer Interrupts . Setting Pthread Priority . Controlling Kernel and User Threads Minimizing Overhead Work . . . Avoid the Clock Processor (CPU 0) Redirect Interrupts . . . . . Restrict, Isolate, and Shield CPUs . Avoid Kernel Module Insertion and Removal Avoid Filesystem Mounts . . . . Understanding Interrupt Response Time Maximum Response Time Guarantee Components of Interrupt Response Time 007–4746–014 . . . . . . . . . . . . . . 45 . . . . . . . . . . . . . . 46 . . . . . . . . . . . . . . . . 47 . . . . . . . . . . . . . . . . 47 . . . . . . . . . . . . . . . . 48 . . . . . . . . . . . . . . . 48 ix Contents Hardware Latency Software Latency . . . . . . . . . . . . . . . . . . . . . . 49 . . . . . . . . . . . . . . . . . . . . . 49 . . . . . . . . . . . . . . . . . . . 50 . . . . . . . . . . . . . . . . . . 50 . . . . . . . . . . . . . . . . . . 51 . . . . . . . . . . . . . . . . . . 51 . . . . . . . . . . . . . . . . . . . 51 . . . . . . . . . . . . . . . . . . . 51 . . . . . . . . . . . . . . . . . 51 . . . . . . 53 Kernel Critical Sections Interrupt Threads Dispatch Device Service . . . . . Interrupt Service Routines User Threads Dispatch Mode Switch . . . . Minimizing Interrupt Response Time 5. Using the Frame Scheduler Frame Scheduler Concepts Frame Scheduler Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 . . . . . . . . . . . . . . . . . . . . 54 . . . . . . . . . . . . . . . . . . . 55 Thread Programming Model Frame Scheduling . . . . . . . . . . . . . . . . . . . . . . 55 Controller Thread . . . . . . . . . . . . . . . . . . . . . . 58 . . . . . . . . . . . . . . . . . . . . . 58 Interrupt Information Templates . . . . . . . . . . . . . . . . . . 59 Library Interface for C Programs . . . . . . . . . . . . . . . . . . 60 Thread Execution . . . . . . . . . . . . . . . . . . 62 . . . . . . . . . . . . . . . . . 64 Scheduler Flags frs_run and frs_yield . . . . . . . . . . . . . . 64 Detecting Overrun and Underrun . . . . . . . . . . . . . . . . . 64 Estimating Available Time . . . . . . . . . . . . . . . . . 65 . . . . . . . . . . . . . . . . . 66 Frame Scheduler API . . . . Scheduling Within a Minor Frame . . Synchronizing Multiple Schedulers Starting a Single Scheduler . . . . . . . . . . . . . . . . . . . 66 Starting Multiple Schedulers . . . . . . . . . . . . . . . . . . . 67 . . . . . . . . . . . . . . . . . . . 67 Pausing Frame Schedulers x . . . . 007–4746–014 REACT Managing Activity Threads Selecting a Time Base . High-Resolution Timer Real-Time for Linux® Programmer’s Guide . . . . . . . . . . . . . . . . . . . 68 . . . . . . . . . . . . . . . . . . . . . 69 . . . . . . . . . . . . . . . . . . . . . 70 . . . . . . . . . . . . . . . . . 70 . . . . . . . . . . . . . . . . . . 71 External Interrupts as a Time Base Using the Scheduling Disciplines Real-Time Discipline TM . . . . . . . . . . . . . . . . . . . . . 71 Underrunable Discipline . . . . . . . . . . . . . . . . . . . . 72 Overrunnable Discipline . . . . . . . . . . . . . . . . . . . . 72 Continuable Discipline . . . . . . . . . . . . . . . . . . . . . 73 Background Discipline . . . . . . . . . . . . . . . . . . . . . 73 . . . . . . . . . . . . . . . 73 . . . . . . . . . . . . . 75 Using Multiple Consecutive Minor Frames Designing an Application for the Frame Scheduler Preparing the System . . . . . . . . . . . . . . . . . . . . . 76 Implementing a Single Frame Scheduler . . . . . . . . . . . . . . . . 77 Implementing Synchronized Schedulers . . . . . . . . . . . . . . . . 78 . . . . . . . . . . . . . . . . . 79 Synchronized Scheduler Concepts . Master Controller Thread . . . . . . . . . . . . . . . . . . . . 79 Slave Controller Thread . . . . . . . . . . . . . . . . . . . . 80 . . . . . . . . . . . . . . . . . 81 Handling Frame Scheduler Exceptions Exception Types . . . . . . . . . . . . . . . . . . . . . . . 81 Exception Handling Policies . . . . . . . . . . . . . . . . . . . 82 Injecting a Repeat Frame . . . . . . . . . . . . . . . . . . . 82 . . . . . . . . . . . . . . . . . . 82 . . . . . . . . . . . . . . . . 83 Extending the Current Frame Dealing With Multiple Exceptions Setting Exception Policies . . . . . . . . . . . . . . . . . . . 83 . . . . . . . . . . . . . . . . . . 84 Using Signals Under the Frame Scheduler . . . . . . . . . . . . . . . . 86 Querying Counts of Exceptions 007–4746–014 . xi Contents Handling Signals in the Frame Scheduler Controller . . . . . . . . . . . . 86 Handling Signals in an Activity Thread . . . . . . . . . . . . . . . . 87 Setting Frame Scheduler Signals Handling a Sequence Error . . . . . . . . . . . . . . . . . . . 87 . . . . . . . . . . . . . . . . . . 88 . . . . . . . . . . . . . . . . 89 . . . . . . 91 Using Timers with the Frame Scheduler 6. Disk I/O Optimization Memory-Mapped I/O Asynchronous I/O . . . . . . . . . . . . . . . . . . . . . . 91 . . . . . . . . . . . . . . . . . . . . . . 91 . . . . . . . . . . . . . . . . . . 92 . . . . . . . . . . . . . . . . . . 92 . . . . . . . 8. User-Level Interrupts . . . . . . . Restrictions on the ULI Handler . . . . . . . . . . . . . . . . . 93 . . . . . . . . . . . . . . . . . 97 . . . . . . . . . . . . . . . . . . 98 . . . . . . . . . . . . . . . . . . 99 . . . . . . . . . . . 101 Planning for Concurrency: Declaring Global Variables Using Multiple Devices . . . . . . . . . . . . . . . . . . . . . 101 . . . . . . . . . . . . . . . . . . . . . 101 . . . . . . . . . . . . . . . . . . 102 Locking the Program Address Space . . . . . . . . . . . . . . . . . 102 Registering the Interrupt Handler . . . . . . . . . . . . . . . . . 103 . . . . . . . . . . . . . . . . . . 103 Setting Up ULI . . . Opening the Device Special File Registering a Per-IRQ Handler Interacting With the Handler . . . . . . . . . . . . . . . . . . . 104 Achieving Mutual Exclusion . . . . . . . . . . . . . . . . . . . 105 . . . . . . 107 . . 107 9. REACT System Configuration react Command-Line Summary xii . . . . . Asynchronous I/O Basics Overview of ULI . . . . Conventional Synchronous I/O 7. PCI Devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 007–4746–014 REACT TM Real-Time for Linux® Programmer’s Guide Initially Configuring REACT . . . . . . . . . . . . . . . . . . . . 109 Changing the Configuration . . . . . . . . . . . . . . . . . . . . 110 Disabling REACT . . . . . . . . . . . . . . . . . . . . . . . 111 Reenabling REACT . . . . . . . . . . . . . . . . . . . . . . . 111 . . . . . . . . . . . . . . . . . . . . 112 . . . . . . . . . . . . . . . . . . . . 112 . . . . . . . . . . . . . . . . 115 . . . . . . . 116 . . . . . . 117 Showing the Configuration Getting Trace Information . Running a Process on a Real-Time CPU Granting Access to REACT Features with react-permissions.pl 10. Using the REACT Library REACT Library Routines cpu_shield . . cpu_sysrt_add . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 . . . . . . . . . . . . . . . . . . . . . . 118 . . . . . . . . . . . . . . . . . . . . . . 119 . . . . . . . . . . . . . . . . . . . . . 120 cpu_sysrt_delete cpu_sysrt_info . . . . . . . . . . . . . . . . . . . . . . 120 cpu_sysrt_irq . . . . . . . . . . . . . . . . . . . . . . 121 cpu_sysrt_perm . . . . . . . . . . . . . . . . . . . . . . 122 cpu_sysrt_runon . . . . . . . . . . . . . . . . . . . . . . 124 Accessing REACT Library Routines . . . . . . . . . . . . . . . . . . 124 . . . . . . . . . . . . . 124 . . . . . . 127 Example Code Using the REACT Library Routines 11. SGI Linux Trace . . . . . . . . . . . . . . Overview of SGI Linux Trace . . . . . . . . . . . . . . . . . . . . 127 Installing SGI Linux Trace . . . . . . . . . . . . . . . . . . . . . 128 Gathering Trace Data . . . . . . . . . . . . . . . . . . . . . 129 . . . . . . . . . . . . . . . . 129 . Invoking the tracevisualizer GUI Recording Events . . Trace Files and Event Types 007–4746–014 . . . . . . . . . . . . . . . . . . . . 130 . . . . . . . . . . . . . . . . . . . 132 xiii Contents Exiting from the tracedaemon Command Line Monitoring Trace Events . . . . . . . . . . . . . 135 . . . . . . . . . . . . . . . . . . . . . 135 . . . . . . . . . . . . . . . . . . . . . 136 Zooming In On An Event . . . . . . . . . . . . . . . . . . . . 136 Changing the Time Frame . . . . . . . . . . . . . . . . . . . . 136 . . . . . . . . . . . . . . . . . . . . 137 Seeing All Event Trace Details . . . . . . . . . . . . . . . . . . 137 Filtering Events Based on CPU . . . . . . . . . . . . . . . . . . 137 Exiting from the tracevisualizer GUI . . . . . . . . . . . . . . . . 137 Removing SGI Linux Trace . . . . . . . . . . . . . . . . 138 . . . . . . 139 Opening a Trace File Seeing Process Details . . . . . 12. Using the SGI Linux Trace User Library SLT User Library Routines slt_close_utrace . . . . . . . . . . . . . . . . . . . . . . . . . . 139 . . . . . . . . . . . . . . . . . . . . . 139 slt_open_utrace . . . . . . . . . . . . . . . . . . . . . . 140 slt_user_trace . . . . . . . . . . . . . . . . . . . . . . 140 . . . . . . . . . . . . . . . . . 141 . . . . . . . . . . . . 141 Accessing SLT User Library Routines Example Code Using the SLT User Library Routines Generating User and Kernel Data Examining the Data . . . . . . . . . . . . . . . . . . . . . . 142 . . . . . . . . . . . . . . . . . . 142 . . . . . . . . . . . . . 143 . . . . . . 145 Manually Including User Events in slt-cpu.all 13. Troubleshooting Diagnostic Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 Problem Removing /rtcpus . . . . . . . . . . . . . . . . . . . . 148 . . . . . . 149 . . 151 Appendix A. Example Application Setting Up External Interrupts xiv . . . . . . . . . . . . . . . . . . . . . . . . . . 007–4746–014 REACT Building and Loading the Kernel Module Matrix Multiply Mode Examples . . . . . . . . . . . . . . . 152 . . . . . . . . . . . . . . . . . 153 . . . . . . . . . . . . . . . . . . 153 . . . . . . . . . . . . . . . . . . 155 . . . . . . . . . . . . . . 155 . . . . . . . . . . . . . . 156 . . . . . . 159 . . . . . . 165 Netlink Socket Benchmark Mode Examples set_affinity code . . . . Real-Time for Linux® Programmer’s Guide . Building the User-Space Application Running the Sample Application TM . . . . Appendix B. High-Resolution Timer Example . . . . . Appendix C. Sample User-Level Interrupt Programs uli_sample Sample Program uli_ei Sample Program Glossary Index . . . . . . . . . . . . . . . . . . . . . . . . 165 . . . . . . . . . . . . . . . . . . . 166 . . . . . . . . . . . . . . . . . . . . . . . . 167 . . . . . . . . . . . . . . . . . . . . . . . . . 177 007–4746–014 xv Figures Figure 3-1 Output and Input Connectors for Interface Circuits of IO9 and PCI-RT-Z Cards Figure 4-1 Components of Interrupt Response Time Figure 5-1 Major and Minor Frames . . . . Figure 8-1 ULI Functional Overview . . . Figure 8-2 ULI Handler Functions . . Figure A-1 Example Work Flow . . 007–4746–014 . 37 . . . . . . . . . . . . 49 . . . . . . . . . . . . . 56 . . . . . . . . . . . . . . 97 . . . . . . . . . . . . . . . 100 . . . . . . . . . . . . . . . 151 xvii Tables Table 3-1 Register Format . . . . . . . . . . . . . . . . . . . 35 Table 5-1 Frame Scheduler Types . . . . . . . . . . . . . . . . . . 58 Table 5-2 Pthread Types . . . . . . . . . . . . . . . . . . 59 Table 5-3 Frame Scheduler Operations . . . . . . . . . . . . . . . . 60 Table 5-4 Activity Thread Functions . . . . . . . . . . . . . . . . 68 Table 5-5 Signals Passed in frs_signal_info_t . . . . . . . . . . . . 87 Table 8-1 Common Arguments for Registration Functions . . . . . . . . . . 98 . . . . . . . . . . 133 Table 11-1 007–4746–014 . . . . Trace Events that are Recorded . . . . . xix Examples Example 3-1 Searching for an Unused External Interrupt Device Example 5-1 Skeleton of an Activity Thread Example 5-2 Alternate Skeleton of an Activity Thread Example 5-3 Function to Set INJECTFRAME Exception Policy Example 5-4 Function to Set STRETCH Exception Policy Example 5-5 Function to Return a Sum of Exception Counts (pthread Model) Example 5-6 Function to Set Frame Scheduler Signals Example 5-7 Minimal Activity Process as a Timer . Example B-1 High-Resolution Timer . 007–4746–014 . . . . . . . . . . . . . . . 21 . . . . . . . . . . . 62 . . . . . . . . . . . 63 . . . . . . . . . 84 . . . . . . . . . 84 . . . . 85 . . . . . . . . . . . . . 88 . . . . . . . . . . . . 89 . . . . . . . . . . . . 159 xxi About This Guide A real-time program is one that must maintain a fixed timing relationship to external hardware. In order to respond to the hardware quickly and reliably, a real-time program must have special support from the system software and hardware. This guide describes the facilities of SGI® REACTTM real-time for Linux®. Audience This guide is written for real-time programmers. You are assumed to be: • An expert in the C programming language • Knowledgeable about the hardware interfaces used by your real-time program • Familiar with system-programming concepts such as interrupts, device drivers, multiprogramming, and semaphores You are not assumed to be an expert in Linux system programming, although you do need to be familiar with Linux as an environment for developing software. What This Guide Contains This guide contains the following: • Chapter 1, "Introduction" on page 1, describes the important classes of real-time programs and applications, summarizes the features that REACT provides, and lists installation requirements • Chapter 2, "Linux and REACT Support for Real–Time Programs" on page 9, provides an overview of how Linux and REACT support real-time programs • Chapter 3, "External Interrupts" on page 17, discusses the external interrupts feature and, as an example, the SGI IOC4 PCI device • Chapter 4, "CPU Workload" on page 39, describes how you can isolate a CPU and dedicate almost all of its cycles to your program’s use 007–4746–014 xxiii About This Guide • Chapter 5, "Using the Frame Scheduler" on page 53, describes how to structure a real-time program as a family of independent, cooperating activities, running on multiple CPUs, scheduled in sequence at the frame rate of the application • Chapter 6, "Disk I/O Optimization" on page 91, describes how to set up disk I/O to meet real-time constraints, including the use of memory-mapped and asynchronous I/O • Chapter 7, "PCI Devices" on page 93, discusses the Linux PCI interface • Chapter 8, "User-Level Interrupts" on page 97, discusses the facility that is intended to simplify the creation of device drivers for unsupported devices • Chapter 9, "REACT System Configuration" on page 107, explains how to configure real-time CPUs • Chapter 10, "Using the REACT Library" on page 117, explains how to use the REACT C application programming interface (API) to change the configuration of real-time CPUs from program control without affecting the boot-up configuration for real-time processing • Chapter 11, "SGI Linux Trace" on page 127, discusses the feature that generates traces for kernel events such as interrupt handling, scheduling, and system calls. • Chapter 12, "Using the SGI Linux Trace User Library" on page 139, explains how to use the SGI Linux Trace (SLT) user library C API to generate SLT user events • Chapter 13, "Troubleshooting" on page 145, discusses diagnostic tools that apply to real-time applications and common problems • Appendix A, "Example Application" on page 149, provides excerpts of application modules to be used with REACT • Appendix B, "High-Resolution Timer Example " on page 159, demonstrates the use of SGI high-resolution timers • Appendix C, "Sample User-Level Interrupt Programs" on page 165, contains a sample program that shows how user-level interrupts are used xxiv 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Related Publications and Sites The following may be useful: • Available from the online SGI Technical Publications Library: – The user guide for your SGI system – SGI Performance Suite 1.0 Start Here – Linux Configuration and Operations Guide – SGI L1 and L2 Controller Software User’s Guide – TP9500 Remote Mirror Premium Feature-Factory – The Linux Programmer’s Guide (Sven Goldt, Sven van der Meer, Scott Burkett, Matt Welsh) – The Linux Kernel (David A Rusling) – Linux Kernel Module Programming Guide (Ori Pomerantz) • Linux Device Drivers, third edition, by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman, February 2005 (ISBN: 0-596-00590-3): http://www.oreilly.com/catalog/linuxdrive3/ For more information about SGI servers, see: • http://www.sgi.com/products/servers 007–4746–014 xxv About This Guide Conventions The following conventions are used throughout this document: Convention Meaning [] Brackets enclose optional portions of a command or directive line. command This fixed-space font denotes literal items such as commands, files, routines, path names, signals, messages, and programming language structures. ... Ellipses indicate that a preceding element can be repeated. manpage(x) Man page section identifiers appear in parentheses after man page names. user input This bold, fixed-space font denotes literal items that the user enters in interactive sessions. (Output is shown in nonbold, fixed-space font.) variable Italic typeface denotes variable entries and words or concepts being defined. ms (or msec) Millisecond (1 ms is .001 seconds) ns Nanosecond (1 ns is .000000001 seconds) us (or usec) Microsecond (1 us is .000001 seconds) Obtaining Publications You can obtain SGI documentation as follows: • See the SGI Technical Publications Library at http://docs.sgi.com. Various formats are available. This library contains the most recent and most comprehensive set of online books, release notes, man pages, and other information. • You can view man pages by typing man title at a command line. xxvi 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Reader Comments If you have comments about the technical accuracy, content, or organization of this publication, contact SGI. Be sure to include the title and document number of the publication with your comments. (Online, the document number is located in the front matter of the publication. In printed publications, the document number is located at the bottom of each page.) You can contact SGI in any of the following ways: • Send e-mail to the following address: techpubs@sgi.com • Contact your customer service representative and ask that an incident be filed in the SGI incident tracking system. • Send mail to the following address: SGI Technical Publications 46600 Landing Parkway Fremont, CA 94538 SGI values your comments and will respond to them promptly. 007–4746–014 xxvii Chapter 1 Introduction This chapter discusses the following: • "Real-Time Programs" on page 1 • "Real-Time Applications" on page 2 • "REACTTM Features" on page 6 • "REACT Requirements" on page 7 • "REACT RPMs" on page 7 Real-Time Programs A real-time program is any program that must maintain a fixed, absolute timing relationship with an external hardware device: • A hard real-time program experiences a catastrophic error if it misses a deadline • A firm real-time program experiences a significant error if it misses a deadline but is able to recover from the error and can continue to execute • A soft real-time program can occasionally miss a deadline with only minor adverse effects A normal-time program is a correct program when it produces the correct output, no matter how long that takes. Normal-time programs do not require a fixed timing relationship to external devices. You can specify performance goals for a normal-time program (such as “respond in at most 2 seconds to 90% of all transactions”), but if the program does not meet the goals, it is merely slow, not incorrect. 007–4746–014 1 1: Introduction Real-Time Applications The following are examples of real-time applications: • "Simulators and Stimulators" on page 2 • "Data Collection Systems" on page 5 • "Process Control Systems" on page 6 Simulators and Stimulators A simulator or a stimulator maintains an internal model of the world. It receives control inputs, updates the model to reflect them, and outputs the changed model. It must process inputs in real time in order to be accurate. The difference between them is that a simulator provides visual output while a stimulator provides nonvisual output. SGI® systems are well-suited to programming many kinds of simulators and stimulators. Simulators and stimulators have the following components: • An internal model of the world, or part of it; for example, a model of a vehicle traveling through a specific geography, or a model of the physical state of a nuclear power plant. • External devices to supply control inputs; for example, a steering wheel, a joystick, or simulated knobs and dials. (This does not apply to all stimulators.) • An operator (or hardware under test) that closes the feedback loop by moving the controls in response to what is shown on the display. A feedback loop provides input to the system in response to output from the system. (This does not apply to all stimulators.) Simulators also have the external devices to display the state of the model; for example, video displays, audio speakers, or simulated instrument panels. The real-time requirements vary depending on the nature of these components. The following are key performance requirements: • Frame rate is the rate at which the simulator updates the display, whether or not the simulator displays its model on a video screen. Frame rate is given in cycles per second (hertz, abbreviated Hz). Typical frame rates run from 15 Hz to 60 Hz, although rates higher and lower than these are used in special situations. 2 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide The inverse of frame rate is frame interval. For example, a frame rate of 60 Hz implies a frame interval of 1/60 second, or 16.67 ms (.01667 seconds). To maintain a frame rate of 60 Hz, a simulator must update its model and prepare a new display in less than 16.67 ms. • Transport delay is the number of frames that elapses before a control motion is reflected in the display. When the transport delay is too long, the operator perceives the simulation as sluggish or unrealistic. If a visual display in a simulator lags behind control inputs, a human operator can become physically ill. In the case where the operator is physical hardware, excessive transport delay can cause the control loop to become unstable. Aircraft Simulators Simulators for real or hypothetical aircraft or spacecraft typically require frame rates of 30 Hz to 120 Hz and transport delays of 1 or 2 frames. There can be several analogue control inputs and possibly many digital control inputs (simulated switches and circuit breakers, for example). There are often multiple video display outputs (one each for the left, forward, and right “windows”) and possibly special hardware to shake or tilt the “cockpit.” The display in the “windows” must have a convincing level of detail. Ground Vehicle Simulators Simulators for automobiles, tanks, and heavy equipment have been built with SGI systems. Frame rates and transport delays are similar to those for aircraft simulators. However, there is a smaller world of simulated “geography” to maintain in the model. Also, the viewpoint of the display changes more slowly, and through smaller angles, than the viewpoint from an aircraft simulator. These factors can make it somewhat simpler for a ground vehicle simulator to update its display. Plant Control Simulators A simulator can be used to train the operators of an industrial plant such as a nuclear or conventional power-generation plant. Power-plant simulators have been built using SGI systems. The frame rate of a plant control simulator can be as low as 1 or 2 Hz. However, the number of control inputs (knobs, dials, valves, and so on) can be very large. Special hardware may be required to attach the control inputs and multiplex them onto the PCI bus. Also, the number of display outputs (simulated gauges, charts, warning 007–4746–014 3 1: Introduction lights, and so on) can be very large and may also require custom hardware to interface them to the computer. Virtual Reality Simulators A virtual reality simulator aims to give its operator a sense of presence in a computer-generated world. A difference between a vehicle simulator and a virtual reality simulator is that the vehicle simulator strives for an exact model of the laws of physics, while a virtual reality simulator typically does not. Usually the operator can see only the simulated display and has no other visual referents. Because of this, the frame rate must be high enough to give smooth, nonflickering animation; any perceptible transport delay can cause nausea and disorientation. However, the virtual world is not required (or expected) to look like the real world, so the simulator may be able to do less work to prepare the display than does a vehicle simulator SGI systems, with their excellent graphic and audio capabilities, are well suited to building virtual reality applications. Hardware-in-the-Loop Simulators The operator of a simulator need not be a person. In a hardware-in-the-loop (HWIL) simulator, the human operator is replaced by physical hardware such as an aircraft autopilot or a missile guidance computer. The inputs to the system under test are the simulator’s output. The output signals of the system under test are the simulator’s control inputs. Depending on the hardware being exercised, the simulator may have to maintain a very high frame rate, up to several thousand Hz. SGI systems are excellent choices for HWIL simulators. Control Law Processor Stimulator An example of a control law processor is one that simulates the effects of Newton’s law on an aircraft flying through the air. When the rudder is turned to the left, the information that the rudder had turned, the velocity, and the direction is fed into the control law processor. The processor calculates and returns a response that represents the physics of motion. The pilot in the simulator cockpit will feel the response and the instruments will show the response. However, a human did not actually interact directly with the processor; it was a machine-to-machine interaction. 4 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Wave Tank Stimulator A wave tank simulates waves hitting a ship model under test. The stimulator must “push” the water at a certain rhythm to keep the waves going. An operator may adjust the frequency and amplitude of the waves, or it could run on a preprogrammed cycle. Data Collection Systems A data collection system receives input from reporting devices (such as telemetry receivers) and stores the data. It may be required to process, reduce, analyze, or compress the data before storing it. It must respond in real time to avoid losing data. SGI systems are suited to many data collection tasks. A data collection system has the following major parts: • Sources of data such as telemetry (the PCI bus, serial ports, SCSI devices, and other device types can be used). • A repository for the data. This can be a raw device (such as a tape), a disk file, or a database system. • Rules for processing. The data collection system might be asked only to buffer the data and copy it to disk. Or it might be expected to compress the data, smooth it, sample it, or filter it for noise. • Optionally, a display. The data collection system may be required to display the status of the system or to display a summary or sample of the data. The display is typically not required to maintain a particular frame rate, however. The first requirement on a data collection system is imposed by the peak data rate of the combined data sources. The system must be able to receive data at this peak rate without an overrun; that is, without losing data because it could not read the data as fast as it arrived. The second requirement is that the system must be able to process and write the data to the repository at the average data rate of the combined sources. Writing can proceed at the average rate as long as there is enough memory to buffer short bursts at the peak rate. You might specify a desired frame rate for updating the display of the data. However, there is usually no real-time requirement on display rate for a data collection system. 007–4746–014 5 1: Introduction That is, the system is correct as long as it receives and stores all data, even if the display is updated slowly. Process Control Systems A process control system monitors the state of an industrial process and constantly adjusts it for efficient, safe operation. It must respond in real time to avoid waste, damage, or hazardous operating conditions. An example of a process control system would be a power plant monitoring and control system required to do the following: • Monitor a stream of data from sensors • Recognize a dangerous situation has occurred • Visualize the key data, such as by highlighting representations of down physical equipment in red and sending audible alarms The danger must be recognized, flagged, and responded to quickly in order for corrective action to be taken appropriately. This entails a real-time system. SGI systems are suited for many process control applications. REACTTM Features REACT real-time for Linux® provides the following features: • SGI Linux Trace debug kernel to provide trace information for analyzing the impact of kernel operations on application performance. • The react command helps you easily generate and configure a real-time system. See Chapter 9, "REACT System Configuration" on page 107. • User-level interrupts to allow you to handle hardware interrupts from a user process. • A frame scheduler that makes it easier to structure a real-time program as a family of independent, cooperating activities that are running on multiple CPUs and are scheduled in sequence at the frame rate of the application. Note: CPU refers to cores (not sockets). 6 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide REACT Requirements REACT requires the following: • One of the following operating systems: – SUSE® Linux® Enterprise Server 11 Service Pack 1 (SLES 11 SP1) or later – Red Hat® Enterprise Linux® 6 (RHEL 6) or later • x86-64 Intel® processors with at least 2 cores (4 cores are preferred) • Sufficient memory so that the system can run the operating system and the real-time applications without swapping For best performance, run REACT on SGI x86-64 servers. Note: Real–time programs using REACT should be written in the C language, which is the most common language for system programming on Linux. REACT RPMs The following RPMs are used for REACT: • Required RPMs: – Cpuset and bitmask: cpuset-utils libbitmask libcpuset – External interrupts (see Chapter 3, "External Interrupts" on page 17): extint sgi-extint-kmp-* 007–4746–014 7 1: Introduction – REACT configuration (see Chapter 9, "REACT System Configuration" on page 107) and library: react-utils – REACT library: libreact – REACT licensing (for react-utils): lk 8 007–4746–014 Chapter 2 Linux and REACT Support for Real–Time Programs This chapter provides an overview of how Linux and REACT support real-time programs: • "Kernel Facilities" on page 9 • "Frame Scheduler" on page 11 • "Clocks and Timers (Altix® UV 1000 and Altix UV 100)" on page 12 • "Interchassis Communication" on page 14 Kernel Facilities The Linux kernel has a number of features that are valuable when you are designing a real-time program. These are described in the following sections: • "Special Scheduling Disciplines" on page 9 • "Virtual Memory Locking" on page 10 • "Processes Mapping and CPUs" on page 10 • "Interrupt Distribution Control" on page 11 Special Scheduling Disciplines The default Linux scheduling algorithm is designed to ensure fairness among time-shared users. The priorities of time-shared threads are largely determined by the following: • Their nice value • The degree to which they are CPU-bound versus I/O-bound 007–4746–014 9 2: Linux and REACT Support for Real–Time Programs While a time-share scheduler is effective at scheduling most standard applications, it is not suitable for real time. For deterministic scheduling, Linux provides the following POSIX real-time policies: • First-in-first-out • Round-robin These policies share a real-time priority band consisting of 99 priorities. For more information about scheduling, see "Real-Time Priority Band" on page 40 and the sched_setscheduler(2) man page. Virtual Memory Locking Linux allows a task to lock all or part of its virtual memory into physical memory so that it cannot be paged out and so that a page fault cannot occur while it is running. Memory locking prevents unpredictable delays caused by paging, but the locked memory is not available for the address spaces of other tasks. The system must have enough physical memory to hold the locked address space and space for a minimum of other activities. Examples of system calls used to lock memory are mlock(2) and mlockall(2). Processes Mapping and CPUs Normally, Linux tries to keep all CPUs busy, dispatching the next ready process to the next available CPU. Because the number of ready processes changes continuously, dispatching is a random process. A normal process cannot predict how often or when it will next be able to run. For normal programs, this does not matter as long as each process continues to run at a satisfactory average rate. However, real-time processes cannot tolerate this unpredictability. To reduce it, you can dedicate one or more CPUs to real-time work by using the following steps: 1. Restrict one or more CPUs from normal scheduling so that they can run only the processes that are specifically assigned to them and isolate them from the effects of scheduler load-balancing. 2. Assign one or more processes to run on the restricted CPUs. A process on a dedicated CPU runs when it needs to run, delayed only by interrupt service and by kernel scheduling cycles. 10 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Interrupt Distribution Control In normal operations, a CPU receives frequent interrupts: • I/O interrupts from devices attached to, or near, the CPU • Timer interrupts that occur on every CPU • Console interrupts that occur on the CPU servicing the system console These interrupts can make the execution time of a process unpredictable. I/O interrupt control is done by /proc filesystem manipulation. For more information on controlling I/O interrupts, see "Redirect Interrupts" on page 43. You can minimize console interrupt effects with proper real-time thread placement. You should not run time-critical threads on the CPU that is servicing the system console. You can see where console interrupts are being serviced by examining the /proc/interrupts file. For example: [root@linux root]# head -1 /proc/interrupts && grep ’SAL console’ /proc/interrupts CPU0 CPU1 CPU2 CPU3 233: 0 12498 0 0 SN hub SAL console driver The above shows that 12,498 console driver interrupts have been serviced by CPU 1. In this case, CPUs 2 and 3 would be much better choices for running time-critical threads because they are not servicing console interrupts. Timer processing is always performed on the CPU from which the timer was started, such as by executing a POSIX timer_settime() call. You can avoid the effects of timer processing by not allowing execution of any threads other than time-critical threads on CPUs that have been designated as such. If your time-critical threads start any timers, the timer processing will result in additional latency when the timeout occurs. Frame Scheduler Many real-time programs must sustain a fixed frame rate. In such programs, the central design problem is that the program must complete certain activities during every frame interval. The frame scheduler is a process execution manager that schedules activities on one or more CPUs in a predefined, cyclic order. The scheduling interval is determined by a repetitive time base, usually a hardware interrupt. 007–4746–014 11 2: Linux and REACT Support for Real–Time Programs The frame scheduler makes it easy to organize a real-time program as a set of independent, cooperating threads. You concentrate on designing the activities and implementing them as threads in a clean, structured way. It is relatively easy to change the number of activities, their sequence, or the number of CPUs, even late in the project. For more information, see Chapter 5, "Using the Frame Scheduler" on page 53. Clocks and Timers (Altix® UV 1000 and Altix UV 100) This section discusses the following for Altix UV 1000 and Altix UV 100: • "Clocks" on page 12 • "Direct RTC Access" on page 14 Clocks Note: This section does not apply to third-party x86-64 or Altix UV 10 servers . SGI Altix UV 1000 and Altix UV 100 systems provide a systemwide clock called a real-time clock (RTC) that is accessible locally on every node. The RTC provides a raw time source that is incremented in 5-ns intervals and using the local APIC timer for timer interrupts (timer_create()), which has a 1–ns resolution. The RTC is 56 bits wide, which ensures that it will not wrap around zero unless the system has been running for more than 11.42 years. RTC values are mapped into the local memory of each node. Multiple nodes accessing the RTC value will not reduce the performance of the clock functions. The RTC is the basis for system time, which may be obtained via the clock_gettime function call that is implemented in conformance with the POSIX standard. clock_gettime takes an argument that describes which clock is wanted. 12 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide The following clock values are typically used: • CLOCK_REALTIME is the actual current time that you would obtain from any ordinary clock. However, CLOCK_REALTIME is set during startup and may be corrected during the operation of the system. This implies that time differences observed by an application using CLOCK_REALTIME may be affected by the initial setting or the later correction of time (via clock_settime) and therefore may not accurately reflect time that has passed for the system. • CLOCK_MONOTONIC starts at zero during bootup and is continually increasing. CLOCK_MONOTONIC will not be affected by time corrections and the initial time setup during boot. If you require a continually increasing time source that always reflects the real time that has passed for the system, use CLOCK_MONOTONIC. The clock_gettime function is a fastcall version that was optimized in assembler and bypasses the context switch typically necessary for a full system call. SGI recommends that you use clock_gettime for all time needs. CLOCK_REALTIME and CLOCK_MONOTONIC report the correct resolution. You can use either CLOCK_REALTIME or CLOCK_MONOTONIC to generate signals via the timer_create() function. To determine the tick frequency, use the sysconf(_SC_CLK_TCK) function. The sysconf(_SC_CLK_TCK) function will always return the right value on Altix UV 1000 and Altix UV 100 systems. 007–4746–014 13 2: Linux and REACT Support for Real–Time Programs Direct RTC Access Note: This section does not apply to third-party x86-64 or Altix UV 10 servers. In some situations, the overhead of the clock_gettime fastcall may be too high. In that case, direct memory-mapped access to the Altix UV 1000 or Altix UV 100 RTC counter is useful. (See the comments in mmtimer.h.) Note: Measurements have shown that the code generated by a function written to obtain the RTC value and then calculate the nanoseconds that have passed is slower than the fastcall for clock_gettime. Direct use of the RTC is only advisable for timestamps. Like CLOCK_MONOTONIC, the RTC counter is monotonically increasing from bootup and is not affected by setting the time. Interchassis Communication This section discusses the following: • "Socket Programming" • "Message-Passing Interface (MPI)" The performance of both sockets and MPI depends on the speed of the underlying network. The network that connects nodes (systems) in an array product has a very high bandwidth. Socket Programming One standard, portable way to connect processes in different computers is to use the BSD-compatible socket I/O interface. You can use sockets to communicate within the same machine, between machines on a local area network, or between machines on different continents. 14 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Message-Passing Interface (MPI) MPI is a standard architecture and programming interface for designing distributed applications. For the MPI standard, see: http://www.mcs.anl.gov/mpi SGI supports MPI. 007–4746–014 15 Chapter 3 External Interrupts Real-time processes often require the ability to react to an external event. External interrupts are a way for a real-time process to receive a real-world external signal. An external interrupt is generated via a signal applied to the external interrupt socket on systems supporting such a hardware feature, such as the IO9 card on an SGI Altix system, which has a 1/8-inch stereo-style jack into which a 0-5V signal can be fed. An exterior piece of hardware can assert this line, causing the card’s IOC4 chip to generate an interrupt. This chapter discusses the following: • "Abstraction Layer" on page 17 • "Making Use of Unsupported Hardware Device Capabilities " on page 31 • "Low-level Driver Template" on page 31 • "Example: SGI IOC4 PCI Device" on page 32 Abstraction Layer Various external interrupt hardware might implement the external interrupt feature in very different ways. The external interrupt abstraction layer provides the ability to determine when an interrupt occurs, to count the number of interrupts, and to select the source of those interrupts without depending upon specifics of the device being used. This section discusses the following: • "sysfs Attribute Files" on page 18 • "The /dev/extint# Device" on page 20 • "Low-Level Driver Interface" on page 23 • "Interrupt Notification Interface" on page 28 007–4746–014 17 3: External Interrupts sysfs Attribute Files The external interrupt abstraction layer provides a character device and the following sysfs attribute files to control operation: File Description dev Contains the major and minor number of the abstracted external interrupt device. If sysfs, hotplug, and udev are configured appropriately, udev will automatically create a /dev/extint# character special device file with this major and minor number. If you prefer, you may manually invoke mknod(1) to create the character special device file. Once created, this device file provides a counter that can be used by applications in a variety of ways. See "The /dev/extint# Device" on page 20. mode Contains the shape of the output signal for interrupt generation. For example, SGI’s IOC4 chip can set the output to one of the following: high, low, pulse, strobe, or toggle. For more information, see "External Interrupt Output" on page 34. modelist Contains the list of available valid output modes, one per line. These strings are the legal valid values that can be written to the mode attribute. For more information, see "External Interrupt Output" on page 34. Note: For the SGI IOC4 chip, there are other values that may be read from the mode attribute file that do not appear in modelist; these represent invalid hardware states. Only the modes present from the modelist are valid settings to be written to the mode attribute. 18 period Contains the repetition interval for periodic output signals (such as repeated strobes, automatic toggling). This period is specified in nanoseconds, and is written as a string. For more information, see "External Interrupt Output" on page 34. provider Contains an indication of which low-level hardware driver and device instance are attached to the external interrupt interface. This string is free-form and is determined by the low-level driver. For example, the SGI IOC4 low-level driver will return a string of the form ioc4_intout#. 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Note: The # value in ioc4_intout# is not necessarily the same number used for extint#, particularly if multiple different low-level drivers are in use (for example, IOC3 and IOC4). quantum Contains the interval to which any writes of the period attribute will be rounded. Because external interrupt output hardware may not support nanosecond granularity for output periods, this attribute allows you to determine the supported granularity. The behavior of the interrupt output (when a value that is not a multiple of the quantum is written to the period attribute) is determined by the specific low-level external interrupt drive. However, generally the low-level driver should round to the nearest available quantum multiple. For example, suppose the quantum value is 7800. If a value of 75000 was written into the period attribute, this would represent 9.6 quantums. The actual period will be rounded to 10 quantums, or 78000 nanoseconds. The actual period will be returned upon subsequent reads from the period attribute. For more information, see "External Interrupt Output" on page 34. source Contains the hardware source of interrupts. For example, SGI’s IOC4 chip can trigger either from the external pin or from an internal loopback from its interrupt output section. sourcelist Contains the list of available interrupt sources, one per line. These strings are the legal values that can be written to the source attribute file. Assuming the usual /sys mount-point for sysfs, the attribute files are located in the following directory: /sys/class/extint/extint#/ The extint# component of the path is determined by the extint driver itself. The # character is replaced by a number (possibly multidigit), one per external interrupt device, beginning at 0. For example, if there were three devices, there would be three directories: /sys/class/extint/extint0/ /sys/class/extint/extint1/ /sys/class/extint/extint2/ 007–4746–014 19 3: External Interrupts The /dev/extint# Device This section discusses the operations that an application can perform with the read-only external interrupt device file /dev/extint#: • "Counting Interrupts" on page 20 • "Waiting for Interrupts" on page 20 • "Exclusively Accessing a Device" on page 20 Counting Interrupts A process may use mmap(2) to memory-map a single memory page from the external interrupt device file into the process’ address space. At the beginning of this page, a counter of an unsigned long type is maintained. This counter is incremented with each external interrupt received by the device. Alternatively, the read(2) system call returns a string representation of the counter’s current value. Waiting for Interrupts The poll(2) and select(2) system calls allow a process to wait for an interrupt to trigger: • poll() indicates whether an interrupt has occurred since the last open(2) or read() of the file • select() blocks until the next interrupt is received Exclusively Accessing a Device The flock(2) system call with the options LOCK_EX|LOCK_MAND ensures exclusive write access to the device attribute files (for example, /sys/class/extint/extint#/mode). Note: You must define the _GNU_SOURCE macro before including the header files in order to use the LOCK_MAND flag on the call to flock(2). When this lock is obtained, only a process that has access to the corresponding file descriptor will be able to write to the attribute files for that device. Any other process 20 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide that attempts a write(2) system call on one of these attribute files will fail with errno set to EAGAIN. The flock() system call will block until there are no other processes that have the device file open and until no other flock() is active on the device. However, if LOCK_NB is passed to flock(), the call will fail and errno will be set to EWOULDBLOCK. While a lock is in place, any attempt to call open(2) on the device will block. However, if O_NONBLOCK is passed to open(), the call will fail and errno will be set to EWOULDBLOCK. To release the lock, call flock() with the LOCK_UN argument. The lock will also be automatically dropped when the last user of the corresponding file descriptor closes the file, including via a process exit. The lock will persist if the file descriptor is inherited across fork(2) or exec(2) system calls. Note: You must not pass the LOCK_MAND flag along with the LOCK_UN flag. The flock() system call behavior is unspecified in this case. Example 3-1 illustrates a method of searching for an unused external interrupt device that can be used exclusively by that program. Example 3-1 Searching for an Unused External Interrupt Device #define _GNU_SOURCE #include#include #include #include #include #include #include #include int main(void) { char devfile[PATH_MAX]; int i = 0; int fd; int found = 0; int status; 007–4746–014 21 3: External Interrupts try_again: /* Search for free /dev/extint# device */ while (i <= 255) { sprintf(devfile, "/dev/extint%d", i); i++; fd = open(devfile, O_RDONLY|O_NONBLOCK); if (fd >= 0) { /* Found a unlocked device. */ found = 1; break; } /* An error occurred. Check why. */ if (EWOULDBLOCK == errno) { /* Found a locked device. */ printf("Tried %s, but it is locked.\n", devfile); } /* Some other type of error, just try next device. * But don’t complain about non-existent devices. */ if (ENOENT != errno) printf("Unexpected error opening %s: %s\n", devfile, strerror(errno)); } if (!found) { printf("Could not find unlocked extint device to use.\n"); return 1; } /* Try locking this device to gain exclusive access. */ status = flock(fd, LOCK_EX|LOCK_MAND|LOCK_NB); if (status != 0) { if (EWOULDBLOCK == errno) { /* The device was available, but another process * has locked it between the time we opened it * and made the flock() call. */ printf("Opened %s, but someone else locked it.\n", devfile); 22 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide } else { /* Some other error occurred. */ printf("Unexpected error locking %s: %s\n", devfile, strerror(errno)); } /* Try the next device. */ found = 0; close(fd); goto try_again; } /* Successfully gained exclusive use of device */ printf("Exclusive use of %s established.\n", devfile); /* Application code begins... */ /* ... application code ends. */ /* Unlock and close external interrupt device */ flock(fd, LOCK_UN); close(fd); /* Successful run */ return 0; } Low-Level Driver Interface The extint_properties and extint_device structures provide the low-level driver interface to the abstraction layer driver. The /usr/local/include/extint.h file defines the structures and function prototypes. This section discusses the following: • "Driver Registration" on page 24 • "Implementation Functions" on page 24 • "When an External Interrupt Occurs" on page 28 • "Driver Deregistration" on page 28 007–4746–014 23 3: External Interrupts Driver Registration To register the low-level driver with the abstraction layer, use the following call: struct extint_device* extint_device_register(struct extint_properties *ep, void *devdata); The ep argument is a pointer to an extint_properties structure that specifies the particular low-level driver functions that the abstraction layer should call when reading/writing the attributes described in "sysfs Attribute Files" on page 18. The devdata argument is an opaque pointer that is stored by the extint code. To retrieve or modify this value, use the following calls: void* extint_get_devdata(const struct extint_device *ed); void extint_set_devdata(struct extint_device *ed, void* devdata); The low-level driver uses this value to determine which of multiple devices it is operating upon. The return value is one of the following: • A pointer to a struct extint_device (which should be saved for later interrupt notification and driver deregistration). • A negative error value (in case of registration failure). The driver should be prepared to deal with such failures. Implementation Functions The struct extint_properties call table is as follows: struct extint_properties { /* Owner module */ struct module *owner; /* Get/set generation mode ssize_t (*get_mode)(struct ssize_t (*set_mode)(struct size_t */ extint_device * ed, char *buf); extint_device * ed, const char *buf, count); /* Get generation mode list */ ssize_t (*get_modelist)(struct extint_device * ed, char *buf); 24 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide /* Get/set generation period */ unsigned long (*get_period)(struct extint_device * ed); ssize_t (*set_period)(struct extint_device * ed, unsigned long period); /* Get low-level provider name */ ssize_t (*get_provider)(struct extint_device *ed, char *buf); /* Generation period quantum */ unsigned long (*get_quantum)(struct extint_device * ed); /* Get/set ingest source */ ssize_t (*get_source)(struct extint_device * ed, char *buf); ssize_t (*set_source)(struct extint_device * ed, const char *buf, size_t count); /* Get ingest source list */ ssize_t (*get_sourcelist)(struct extint_device * ed, char *buf); /* Arm/disarm timer */ int64_t (*arm_timer)(struct extint_device * ed, int64_t ns, int when); void (*disarm_timer)(struct extint_device * ed); }; Note: Additional fields not of interest to the low-level external interrupt driver may be present. You should include /usr/local/include/extint.h to acquire these structure definitions. The owner value should be set to the module that contains the functions pointed to by the remaining structure members. The remaining functions implement low-level aspects of the abstraction layer attributes. They all take a pointer to the struct extint_device as was returned from the registration function. In all of these functions, you can retrieve the value passed as the devdata argument to the registration function by using the following call: extint_get_devdata(ed); You can update the value by using the following call: extint_set_devdata(ed, newvalue); 007–4746–014 25 3: External Interrupts Typically, this value is a pointer to driver-specific data for the individual device being operated upon. It may, for example, contain pointers to mapped PCI regions where control registers reside. 26 Field Description owner Specifies the module that contains the functions pointed to by the remaining structure members. get_mode Writes the current mode attribute of the abstraction layer into the single-page-sized buffer passed as the second argument and returns the length of the written string. set_mode Reads the mode attribute of the abstraction layer as specified in the buffer (passed as the second argument and as sized by the third) and returns the number of characters consumed (or a negative error number in event of failure). It also causes the output mode to be set as requested. get_modelist Writes strings representing the available interrupt output generation modes into the single-page-sized buffer passed as the second argument, one mode per line. It returns the number of bytes written into this buffer. This implements the modelist attribute of the abstraction layer. get_period Returns an unsigned long that represents the current repetition period, in nanoseconds. This implements the period attribute of the abstraction layer. set_period Accepts an unsigned long as the new value for the repetition period, specified in nanoseconds, and returning either 0 or a negative error number indicating a failure. If the requested repetition period is not a value that can be exactly set into the underlying hardware, the driver is free to adjust the value as it sees fit, although typically it should round the value to the nearest available value. This implements the period attribute of the abstraction layer. get_provider Writes a human-readable string that identifies the low-level driver and a particular instance of a driven hardware device. For example, if the low-level driver 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide provides its own additional device files for extra functionality not present in the abstraction layer, this routine might emit the name of the driver module and the names (or device numbers) of the low-level driver’s own character special device files. This implements the provider attribute of the abstraction layer. 007–4746–014 get_quantum Returns an unsigned long that represents the granularity to which the interrupt output repetition period can be set, in nanoseconds. This implements the quantum attribute of the abstraction layer. get_source Writes the current interrupt input source into the single-page-sized buffer passed as the second argument and returns the length of the written string. This implements the source attribute of the abstraction layer. set_source Reads the source specified in the buffer (passed as the second argument and as sized by the third) and returns the number of characters consumed or a negative error number in event of failure. It also causes the input source to be selected as requested. This implements the source attribute of the abstraction layer. get_sourcelist Writes strings representing the available interrupt input sources into the single-page-sized buffer passed as the second argument, one source per line. It returns the number of bytes written into this buffer. This implements the sourcelist attribute of the abstraction layer. arm_timer Sets up the external interrupt device to generate an interrupt at a specified time. The time is specified in nanoseconds via the second argument. The third parameter may be set to the values EXTINT_TIMER_RELATIVE or EXTINT_TIMER_ABSOLUTE. The third parameter controls whether the time is relative to the moment the function is called or is absolute system time, (as returned by the getnstimeofday() system call). Interrupt notifications occur through the standard external interrupt callout mechanism described in 27 3: External Interrupts "Interrupt Notification Interface" on page 28. This field may be set to NULL if the low-level driver does not support timer functionality. disarm_timer Cancels a pending interrupt, if any, scheduled to be delivered due to a prior call to the arm_timer() function. If the previously scheduled interrupt has already occurred, it is not necessary to call disarm_timer(), and calling disarm_timer() when no interrupt is pending should be harmless. This field may be set to NULL if the low-level driver does not support timer functionality. When an External Interrupt Occurs When an external interrupt signal triggers an interrupt that is handled by the low-level driver, the driver should make the following call: void extint_interrupt(struct extint_device *ed); This allows the abstraction layer to perform any appropriate abstracted actions, such as update the interrupt count or trigger poll/select actions. The sole argument is the struct extint_device that was returned from the registration call. Driver Deregistration When the driver desires to deregister a particular device previously registered with the abstraction layer, it should make the following call: void extint_device_unregister(struct extint_device *ed); The sole argument is the struct extint_device that was returned from the registration call. There is no error return from this call, but if invalid data is passed to it, the likelihood of a kernel panic is very high. Interrupt Notification Interface In addition to the user-visible aspects of the external interrupt abstraction layer, there is a kernel-only interface available for interrupt notification. This interface provides 28 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide the ability for other kernel modules to register a callout to be invoked whenever an external interrupt is ingested for a particular device. This section discusses the following: • "Callout Mechanism" on page 29 • "Callout Registration" on page 29 • "Callout Deregistration" on page 30 Callout Mechanism For systems (not just applications) that are critically interested in responding as quickly as possible to an externally triggered event, waiting for a poll/select operation, or even busy-waiting on the value of the interrupt counter to change, may have unexpected harmful effects (such as tying up a CPU spinning on a value) or may not provide appropriate response times. A callout mechanism lets you write your own kernel module in order to gain minimal-latency notification of events and react accordingly. It also provides an extension capability that might be of interest in certain situations. For example, there could be an application that requires an interrupt counter page similar to the one maintained by the abstraction layer, but that starts counting at 0 when the device special file is opened. Or, there could be an application that requires a signal to be generated and delivered to the process when an interrupt is ingested. These examples are more esoteric than the simple counter page, and are best provided by a separate module rather than cluttering the main external interrupt abstraction code. Callout Registration To register a callout to be invoked upon interrupt ingest, allocate a struct extint_callout, fill it in, and pass it to the following call: int extint_callout_register(struct extint_device *ed, struct extint_callout *ec); The first argument is the struct extint_device corresponding to the particular abstracted external interrupt hardware device of interest. How this structure is found is up to the caller; however, the file_to_extint_device function will convert a struct file pointer to a struct extint_device pointer. This function will return -EINVAL if an inappropriate file descriptor is passed to it. 007–4746–014 29 3: External Interrupts The second argument is one of the following structures: struct extint_callout { struct module* owner; void (*function)(void *); void *data; }; Note: Additional fields not of interest to the external interrupt user may be present. You should include /usr/local/include/extint.h to acquire these structure definitions. The owner field should be set to the module containing the function and data pointed to by the remaining fields. The function pointer is a callout function that is to be invoked whenever an interrupt is ingested by the abstraction layer for the device of interest. The data field is the only argument passed to it; it is used opaquely and is provided solely for use by the caller. That is, the abstraction layer will invoke the following upon each interrupt of the specified device: ec->function(data); You can register multiple callouts for the same abstracted external interrupt device. They will be invoked in no guaranteed order, but will be invoked one at a time. The interrupt counter will be incremented before the callouts are invoked, but before any signal/poll notifications occur. The module specified by the owner field in the callout structure, as well as the module corresponding to the low-level external interrupt device driver, will have their reference counts increased by one until the callout is deregistered. Callout Deregistration To remove a callout, call the following with the same arguments as provided during callout registration: extern void extint_callout_unregister(struct extint_device *ed, struct extint_callout *ec); 30 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide You can remove both active and orphaned callouts in this manner with no distinction between the two. The callout function must continue to be able to be invoked until the call to extint_callout_unregister completes. Making Use of Unsupported Hardware Device Capabilities If your hardware device supports capabilities that are not provided for in the abstraction layer, you can do one of the following: • Add a new attribute to the abstraction layer by modifying struct extint_properties to add appropriate interface routines and update any existing drivers as necessary. • Have the low-level driver create its own device class and corresponding attributes and/or character special devices. This method is preferred and is required if the capability is dependent on the hardware in a method that cannot be abstracted. For example, the SGI IOC4 has the ability to map the interrupt output control register directly into a user application to avoid the kernel overhead of reading/writing the abstracted attribute files. Using this capability means that the application must have intimate knowledge of the format of the control register, something that cannot be abstracted away by the kernel and is very specific to this particular I/O controller chip. This capability is provided by the ioc4_extint driver, which supplies its own character special device along with an ioc4_intout device class. Low-level Driver Template You can use the ioc4_extint.c file as a template for a low-level driver. The file is shipped as part of the extint source RPM. Note: In addition to providing the abstraction interface, this low-level driver creates an IOC4-specific character special device and an IOC4-specific device class. 007–4746–014 31 3: External Interrupts Example: SGI IOC4 PCI Device This section describes the following for the SGI IOC4 PCI device: • "Multiple Independent Drivers" on page 32 • "External Interrupt Output" on page 34 • "External Interrupt Ingest" on page 36 • "Physical Interfaces" on page 36 For more information, see the Documentation/sgi-ioc4.txt file, which is installed with the Linux source code corresponding to the real-time kernel. Multiple Independent Drivers The IOC4 external interrupt driver is not a typical PCI device driver. Due to certain design features of the IOC4 controller, typical PCI probing and removal functions are not appropriate. Instead, the IOC4 external interrupt driver interfaces with a core IOC4 driver that takes care of the usual PCI-level driver functionality. (An overview is provided below; for more details, see the Documentation/sgi-ioc4.txt file in the kernel source code.) However, the IOC4 external interrupt driver does interface very cleanly with the external interrupt abstraction layer, which is within the scope of the following discussion. The IOC4 driver actually consists of the following independent drivers: ioc4 The core driver for IOC4. It is responsible for initializing the basic functionality of the chip and allocating the PCI resources that are shared between the IOC4 functions. This driver also provides registration functions that the other IOC4 drivers can call to make their presence known. Each driver must provide a probe and a remove function, which are invoked by the core driver at appropriate times. The interface for the probe and remove operations is not precisely the same as the PCI device probe and remove operations, but is logically the same operation. 32 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide sgiioc4 The IDE driver for IOC4. It hooks up to the ioc4 driver via the appropriate registration, probe, and remove functions. ioc4_serial The serial driver for IOC4. It hooks up to the ioc4 driver via the appropriate registration, probe, and remove functions. ioc4_extint The external interrupts driver for IOC4. IOC4-based I/O controller cards provide an electrical interface to the outside world that can be used to ingest and generate a simple signal for the following purposes: • On the output side, one of the jacks can provide a small selection of output modes (low, high, a single strobe, toggling, and pulses at a specified interval) that create a 0-5V electrical output. • On the input side, one of the jacks will cause the IOC4 to generate a PCI interrupt on the transition edge of an electrical signal. This driver registers with the extint abstracted external interrupt driver and lets it take care of the user-facing details. 007–4746–014 33 3: External Interrupts External Interrupt Output The output section provides several modes of output: Mode Description high Sets the output to logic high. The high state of the card’s electrical output is actually a low voltage (0V). low Sets the output to logic low. The low state of the card’s electrical output is actually a high voltage (+5V). pulse Sets the output to logic high for 3 ticks then returns to logic low for an interval configured by the period setting, then repeats. The mode is configurable by the abstraction layer device’s mode attribute. The abstraction layer device’s modelist attribute contains available modes. strobe Sets the output to logic high for 3 ticks, then returns to logic low. A tick is the PCI clock signal divided by 520. toggle Alternates the output between logic low and logic high as configured by the period setting. The period can be set to a range of values determined by the PCI clock speed of the IOC4 device. For the toggle and pulse output modes, this period determines how often the toggle or pulse occurs. The output period can be set only to a multiple of this length (rounding will occur automatically in the driver). The pulse and strobe output modes have a logic high pulse width equal to three ticks. The period should be configurable by the abstraction layer device’s period attribute, and the tick length can be found from the abstraction layer device’s quantum attribute. Note: For reference, on a 66-MHz PCI bus, the tick length is 7.8 microseconds. On a 33-MHz PCI bus, the tick length is 15.6 microseconds. However, the IOC4 driver calibrates itself to a more precise value than these somewhat coarse numbers, depending on actual bus speed, which may vary slightly from bus to bus or even reboot to reboot. However, IOC4 is only officially supported when running at 66-MHz. One device file is provided, which can be memory mapped. The first 32-bit quantity in the mapped area is aliased to the hardware register that controls output. Direct manipulation of the register, both for reading and writing, may be performed in order to avoid the kernel overhead that would be necessary if using the abstracted 34 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide interfaces. Assuming the typical sysfs mount point, the device number files for these devices can be found at: /sys/class/ioc4_intout/intout#/dev This capability is not abstracted into the external interrupt abstraction layer because it is critical for an application to know that this is an IOC4 device in order to determine the format of the mapped register. Table 3-1 shows the register format. Table 3-1 Register Format Bits Field Read/Write Options Description 15:0 COUNT RW Reloaded into the counter each time it reaches 0x0. The count period is actually (COUNT+1). 18:16 MODE RW Sets the mode for INT_OUT control: • • • • • • 000 loads a 0 to INT_OUT 100 loads a 1 to INT_OUT 101 pulses INT_OUT high for 3 ticks 110 pulses INT_OUT for 3 ticks every COUNT 111 toggles INT_OUT for 3 ticks every COUNT 001, 010, and 011 are undefined 29:19 (reserved) RO Read as 0, writes are ignored. 30 DIAG RW Bypass clock base divider. Operation when DIAG is set to a value of 1 is strictly unsupported. 31 INT_OUT RO Current state of INT_OUT signal. Note: There are the following considerations: • The register should always be read and written as a 32-bit word in order to avoid concerns about big-endian and little-endian differences between the CPU and the IOC4 device. • The /dev/intout# file may be memory-mapped only on kernels with a system page size of 16 KB or smaller. Due to technical constraints, it is not made available on kernels with a system page size larger than 16 KB. 007–4746–014 35 3: External Interrupts External Interrupt Ingest The ingest section provides one control, the source of interrupt signals. The external source is a circuit connected to the external jack provided on IOC4-based I/O controller cards. The loopback source is the output of the IOC4’s interrupt output section. The source is configurable by the abstraction layer device’s source attribute. You can find available sources in the abstraction layer device’s sourcelist attribute. For example, to set up loopback mode: [root@linux root]# echo loopback >/sys/class/extint/extint0/source [root@linux root]# echo 100000000 >/sys/class/extint/extint0/period [root@linux root]# echo toggle >/sys/class/extint/extint0/mode Note: The IO10 card does not provide the 1/8–inch stereo connector interface for external interrupts, and thus can only use loopback as its source. Physical Interfaces Use a two-conductor shielded cable to connect external interrupt output and input, with the two cable conductors wired to the +5V and interrupt conductors and the sleeves connected to the cable shield at both ends to maintain EMI integrity. All IOC4-based external interrupt implementations use female 1/8-inch audio jacks. The wiring for the input jack is as follows: • Tip: +5V input • Ring: interrupt input (active low, optoisolated) • Sleeve: chassis ground/cable shield The input signal passes through an optoisolator that has a damping effect. The input signal must be of sufficient duration to drive the output of the optoisolator low in order for the interrupt to be recognized by the receiving machine. Current experimentation shows that the threshold is about 2.5 microseconds. To be safe, the driver sets its default outgoing pulse width to 10 microseconds. Any hardware not from SGI that is driving this line should do the same. Figure 3-1 shows the internal driver circuit for the output connector and the internal receiver circuit for the input connector. 36 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Internal driver circuit output connector +5V Output +5V connector Output interrupt connector open collector driver Ground Internal driver circuit input connector Input +5V connector Optoisolator LED Input interrupt connector Figure 3-1 Output and Input Connectors for Interface Circuits of IO9 and PCI-RT-Z Cards You can wire an output connector directly to an input connector, taking care to connect the +5V output to the +5V input and the interrupt output to the interrupt input. If some other device is used to drive the input, it must be a it must be a +5V source current-limited with series resistor of at least 420 ohms in order to avoid damaging the optoisolator. Note: The resistor on the output circuit of IO9 and PCI-RT-Z cards is 470 ohms. To protect the input circuit on these cards from damage, a resistor of at least 420 ohms is required. 007–4746–014 37 Chapter 4 CPU Workload This chapter describes how to use Linux kernel features to make the execution of a real-time program predictable. Each of these features works in some way to dedicate hardware to your program’s use, or to reduce the influence of unplanned interrupts on it: • "Using Priorities and Scheduling Queues" on page 39 • "Minimizing Overhead Work" on page 43 • "Understanding Interrupt Response Time" on page 47 • "Minimizing Interrupt Response Time" on page 51 Using Priorities and Scheduling Queues The default Linux scheduling algorithm is designed for a conventional time-sharing system. It also offers additional real-time scheduling disciplines that are better-suited to certain real-time applications. This section discusses the following: • "Scheduling Concepts" on page 39 • "Setting Pthread Priority" on page 41 • "Controlling Kernel and User Threads" on page 42 Scheduling Concepts In order to understand the differences between scheduling methods, you must understand the following basic concepts: • "Timer Interrupts" on page 40 • "Real-Time Priority Band" on page 40 For information about time slices and changing the time-slice duration, see the information about the CPU scheduler in the Linux Configuration and Operations Guide. 007–4746–014 39 4: CPU Workload Timer Interrupts In normal operation, the kernel pauses to make scheduling decisions every several millisecond (ms) in every CPU. You can determine the frequency of this interval with the sysconf(_SC_CLK_TCK) function (see "Clocks" on page 12). Every CPU is normally interrupted by a timer every timer interval. (However, the CPUs in a multiprocessor are not necessarily synchronized. Different CPUs may take timer interrupts at different times.) During the timer interrupt, the kernel updates accounting values, does other housekeeping work, and chooses which process to run next—usually the interrupted process, unless a process of superior priority has become ready to run. The timer interrupt is the mechanism that makes Linux scheduling preemptive; that is, it is the mechanism that allows a high-priority process to take a CPU away from a lower-priority process. Before the kernel returns to the chosen process, it checks for pending signals and may divert the process into a signal handler. Real-Time Priority Band A real-time thread can select one of a range of 99 priorities (1-99) in the real-time priority band, using POSIX interfaces sched_setparam() or sched_setscheduler(). The higher the numeric value of the priority, the more important the thread. For more information, see the sched_setscheduler(2) man page. Many soft real-time applications must execute ahead of time-share applications, so a lower priority range is best suited. Because time-share applications are scheduled at lower priority than real-time applications, a thread running at the lowest real-time priority (1) still executes ahead of all time-share applications. Note: Applications cannot depend on system services if they are running ahead of system threads without observing system-responsiveness timing guidelines. 40 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Within a program it is usually best to follow the principles of rate-monotonic scheduling. However, you can use the following list as a guideline for selecting scheduling priorities in order to coordinate among different programs: Priority Description 99 Reserved for critical kernel threads and should not be used by applications (99 is the highest real-time priority) 90 - 98 Hard real-time user threads 60 - 89 High-priority operating system services 40 - 59 Firm real-time user threads 31 - 39 Low-priority operating system services 1 - 30 Soft real-time user threads Real-time users can use tools such as strace(1) and ps(1) to observe the actual priorities and dynamic behaviors. Setting Pthread Priority The Linux pthreads library shipped with SLES and RHEL is known as the new pthreads library (NPTL). By default, a newly created pthread receives its priority from the same scheduling policy and scheduling priority as the pthread that created it; new pthreads will ignore the values in the attributes structure. 007–4746–014 41 4: CPU Workload You can set the priority and scheduling policy of pthreads as follows: • To change a running pthread, the pthread must call pthread_setschedparam(). • To set the scheduling attributes that a pthread will start with when it is created, use the pthread_attr_setschedpolicy() and pthread_attr_setschedparam() library calls to configure the attributes structure that will later be passed to pthread_create(). The pthread_attr_setinheritsched() library call acts on the pthread_attr_t structure that will later be passed to pthread_create(). You can configure it with one of the following settings: – PTHREAD_EXPLICIT_SCHED causes pthreads to use the scheduling values set in the structure – PTHREAD_INHERIT_SCHED causes pthreads to inherit the scheduling values from their parent pthread Controlling Kernel and User Threads In some situations, kernel threads and user threads must run on specific processors or with other special behavior. Most user threads and a number of kernel threads do not require any specific CPU or node affinity, and therefore can run on a select set of nodes. The SGI bootcpuset feature controls the placement of both kernel and user threads that do not require any specific CPU or node affinity. By placing these threads out of the way of your time-critical application threads, you can minimize interference from various external events. As an example, an application might have two time-critical interrupt servicing threads, one per CPU, running on a four-processor machine. You could set up CPUs 0 and 1 as a bootcpuset and then run the time-critical threads on CPUs 2 and 3. Note: You must have the SGI cpuset-*.rpm RPM installed to use bootcpusets. For configuration information, see the bootcpuset(8) man page. You can use the react command to configure the real-time CPUs; see Chapter 9, "REACT System Configuration" on page 107. 42 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Minimizing Overhead Work A certain amount of CPU time must be spent on general housekeeping. Because this work is done by the kernel and triggered by interrupts, it can interfere with the operation of a real-time process. However, you can remove almost all such work from designated CPUs, leaving them free for real-time work. First decide how many CPUs are required to run your real-time application. Then apply the following steps to isolate and restrict those CPUs: • "Avoid the Clock Processor (CPU 0)" on page 43 • "Redirect Interrupts" on page 43 • "Restrict, Isolate, and Shield CPUs" on page 44 • "Avoid Kernel Module Insertion and Removal" on page 46 • "Avoid Filesystem Mounts" on page 47 Note: The steps are independent of each other, but each must be done to completely free a CPU. Avoid the Clock Processor (CPU 0) Every CPU takes a timer interrupt that is the basis of process scheduling. However, CPU 0 does additional housekeeping for the whole system on each of its timer interrupts. Therefore, you should not to use CPU 0 for running real-time processes. Redirect Interrupts To minimize latency of real-time interrupts, it is often necessary to direct them to specific real-time processors. It is also necessary to direct other interrupts away from specific real-time processors. This process is called interrupt redirection. You can use the react command to redirect interrupts; for more information, see Chapter 9, "REACT System Configuration" on page 107. Note: SGI recommends that someone with knowledge of the system configuration use react to redirect only the interrupts that must be moved. 007–4746–014 43 4: CPU Workload The process involves writing a hexadecimal bitmask to the /proc/irq/interruptnumber/smp_affinity file, which shows a bitmask of the CPUs that are allowed to receive this interrupt. A 1 in the least-significant bit in this mask denotes that CPU 0 is allowed to receive the interrupt. The most-significant bit denotes the highest-possible CPU that the booted kernel could support. For example, to redirect interrupt 62 to CPU 1, enter the following: [root@linux root]# echo 1 > /proc/irq/62/smp_affinity To view the IRQ/CPU affinity, use the less command to view the smp_affinity file. For example: [root@linux root]# less /proc/irq/62/smp_affinity Note: To avoid any potential viewing problems, you should use less(1) rather than cat(1) to view the smp_affinity file. You can examine the /proc/interrupts file to discover where interrupts are being received on your system. Restrict, Isolate, and Shield CPUs In general, the Linux scheduling algorithms run a process that is ready to run on any CPU. For best performance of a real-time process or for minimum interrupt response time, you must use one or more CPUs without competition from other scheduled processes. You can exert the following levels of increasing control: • Restricted and isolated, which prevents the CPU from running scheduled processes and removes the CPU from load balancing considerations, a time-consuming scheduler operation. • Shielded, which switches off the timer (scheduler) interrupts that would normally be scheduled on the CPU. These are a source of jitter, but only a minor source of interrupt response latency. Shielding should only be done for short periods where basically jitter-free program execution is required. You should use the react command to create a real-time CPU that is restricted and isolated. For more information, see Chapter 9, "REACT System Configuration" on page 107. 44 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide You can also use the REACT C application programming interface (API) to restrict and isolate a CPU. See Chapter 10, "Using the REACT Library" on page 117. Restricting a CPU from Scheduled Work and Isolating it from Scheduler Load Balancing You can restrict one or more CPUs from running scheduled processes and isolate them from scheduler load balancing by designating them as realtime CPUs with the react command. The only processes that can use a restricted CPU are those processes that you assign to it, along with certain per-CPU kernel threads. Isolating a CPU removes one source of unpredictable delays from a real-time program and helps further minimize the latency of interrupt handling. To restrict one or more CPUs, use the react -r command documented in Chapter 9, "REACT System Configuration" on page 107. After restricting a CPU, you can assign processes to it using the SGI cpuset command. See "Running a Process on a Real-Time CPU" on page 115. Each rtcpu is set to be cpu_exclusive. To remove the CPU restriction, allowing the CPU to execute any scheduled process, see "Changing the Configuration" on page 110. Shielding a CPU from Timer Interrupts You can shield a CPU from the normally scheduled Linux timer (scheduler) interrupts. For more information on timer interrupts, see "Timer Interrupts" on page 40. Timer interrupts are a source of interrupt response latency (usually several usec). Shielding is done dynamically from program control, and should only be done for short periods where essentially jitter-free program execution is required. When a CPU’s timer interrupts are switched off, scheduling on that CPU ceases. A thread must not yield the CPU (sleep) unless it expects to be awoken by an external event such as an I/O interrupt or if timer interrupts will be switched back on before it must be scheduled again. 007–4746–014 45 4: CPU Workload Note: Be aware of the following: • Prolonged periods of shielding might eventually result in system resource depletion. System resource depletion usually takes the form of out-of-memory conditions, eventually causing forced shutdown of the application. The kernel ring buffer will indicate this situation by showing a stack trace for the application and a No available memory in cpuset: message. To view the kernel ring buffer, run the dmesg command. • You should ensure that all threads are placed in their appropriate cpusets prior to calling cpu_shield() anywhere on the system. Movement between cpusets will be held off during periods where any processor’s timer interrupts are switched off. After timer interrupts for all processors are switched back on, any pending cpuset thread movement will occur. To shield a CPU from timer interrupts, do the following: 1. Load the sgi-shield kernel module. For example: [root@linux root]# modprobe sgi-shield 2. From your application, call the cpu_shield() function with the SHIELD_STOP_INTR flag and the desired CPU number. Your program must link in the libreact library to access the cpu_shield() function. For more information, see the libreact(3) man page. For example, to switch off timer interrupts on CPU 3, perform the following function call from the application: cpu_shield(SHIELD_STOP_INTR, 3) To unshield the CPU, call the cpu_shield() function with the SHIELD_START_INTR flag and the desired CPU number. For example, when shielding CPU 3 is no longer necessary, perform the following call from the application: cpu_shield(SHIELD_START_INTR, 3) Avoid Kernel Module Insertion and Removal The insertion and removal of Linux kernel modules (such as by using modprobe or insmod/rmmod) requires that a kernel thread be started on all active CPUs (including 46 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide isolated CPUs) in order to synchronously stop them. This process allows safe lockless-module list manipulation. However, these kernel threads can interfere with thread wakeup and, for brief periods, the ability to receive interrupts. While a time-critical application is running, you must avoid Linux kernel module insertion and removal. All necessary system services should be running prior to starting time-critical applications. Avoid Filesystem Mounts The process of mounting/unmounting a filesystem (including an NFS filesystem) can interfere with response times for a number of CPUs. These delays do not happen after the mount has completed. There is no delay for disk accesses. Prior to running a time-critical application, you should complete all filesystem mounts that may be necessary during application execution. Filesystem unmounts during application execution should be avoided. This includes autofs mounts performed by automount. Understanding Interrupt Response Time Interrupt response time is the time that passes between the instant when a hardware device raises an interrupt signal and the instant when (interrupt service completed) the system returns control to a user process. SGI guarantees a maximum interrupt response time on certain systems, but you must configure the system properly in order to realize the guaranteed time. This section discusses the following: • "Maximum Response Time Guarantee" on page 48 • "Components of Interrupt Response Time" on page 48 007–4746–014 47 4: CPU Workload Maximum Response Time Guarantee In properly configured systems, interrupt response time is guaranteed not to exceed 30 microseconds (usecs) for SGI x86–64 systems running Linux. This guarantee is important to a real-time program because it puts an upper bound on the overhead of servicing interrupts from real-time devices. You should have some idea of the number of interrupts that will arrive per second. Multiplying this by 30 usecs yields a conservative estimate of the amount of time in any one second devoted to interrupt handling in the CPU that receives the interrupts. The remaining time is available to your real-time application in that CPU. Components of Interrupt Response Time The total interrupt response time includes the following sequential parts: Time Description Hardware latency The time required to make a CPU respond to an interrupt signal. See "Hardware Latency" on page 49. Software latency The time required to dispatch an interrupt thread. See "Software Latency" on page 49. Device service The time the device driver spends processing the interrupt and dispatching a user thread. See "Device Service" on page 51. Mode switch The time it takes for a thread to switch from kernel mode to user mode. See "Mode Switch" on page 51. Figure 4-1 diagrams the parts discussed in the following sections. 48 007–4746–014 TM REACT Device Raises Interrupt Enter Interrupt Dispatch Hardware Latency Enter Device Driver Software Latency Dispatch Interrupt Thread Real-Time for Linux® Programmer’s Guide Exit Device Driver Device Service Interrupt Service Routine Enter User Code Mode Switch Dispatch User Thread Kernel Critical Section Figure 4-1 Components of Interrupt Response Time Hardware Latency When an I/O device requests an interrupt, it activates a line in the PCI bus interface. The bus adapter chip places an interrupt request on the system internal bus and a CPU accepts the interrupt request. The time taken for these events is the hardware latency, or interrupt propagation delay. For more information, see Chapter 7, "PCI Devices" on page 93. Software Latency Software latency is affected by the following: • "Kernel Critical Sections" on page 50 • "Interrupt Threads Dispatch" on page 50 007–4746–014 49 4: CPU Workload Kernel Critical Sections Certain sections of kernel code depend on exclusive access to shared resources. Spin locks are used to control access to these critical sections. Once in a critical section, interrupts are disabled. New interrupts are not serviced until the critical section is complete. There is no guarantee on the length of kernel critical sections. In order to achieve 30-usec response time, your real-time program must avoid executing system calls on the CPU where interrupts are handled. The way to ensure this is to restrict that CPU from running normal processes. For more information, see "Restricting a CPU from Scheduled Work and Isolating it from Scheduler Load Balancing" on page 45. You may need to dedicate a CPU to handling interrupts. However, if the interrupt-handling CPU has power well above that required to service interrupts (and if your real-time process can tolerate interruptions for interrupt service), you can use the restricted CPU to execute real-time processes. If you do this, the processes that use the CPU must avoid system calls that do I/O or allocate resources, such as fork(), brk(), or mmap(). The processes must also avoid generating external interrupts with long pulse widths. In general, processes in a CPU that services time-critical interrupts should avoid all system calls except those for interprocess communication and for memory allocation within an arena of fixed size. Interrupt Threads Dispatch The primary function of interrupt dispatch is to determine which device triggered the interrupt and dispatch the corresponding interrupt thread. Interrupt threads are responsible for calling the device driver and executing its interrupt service routine. While the interrupt dispatch is executing, all interrupts at or below the current interrupt’s level are masked until it completes. Any pending interrupts are dispatched before interrupt threads execute. Thus, the handling of an interrupt could be delayed by one or more devices. In order to achieve 30-usec response time on a CPU, you must ensure that the time-critical devices supply the only device interrupts directed to that CPU. For more information, see "Redirect Interrupts" on page 43. 50 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Device Service Device service time is affected by the following: • "Interrupt Service Routines" • "User Threads Dispatch" Interrupt Service Routines The time spent servicing an interrupt should be negligible. The interrupt handler should do very little processing; it should only wake up a sleeping user process and possibly start another device operation. Time-consuming operations such as allocating buffers or locking down buffer pages should be done in the request entry points for read(), write(), or ioctl(). When this is the case, device service time is minimal. User Threads Dispatch Typically, the result of the interrupt is to make a sleeping thread runnable. The runnable thread is entered in one of the scheduler queues. This work may be done while still within the interrupt handler. Mode Switch A number of instructions are required to exit kernel mode and resume execution of the user thread. Among other things, this is the time when the kernel looks for software signals addressed to this process and redirects control to the signal handler. If a signal handler is to be entered, the kernel might have to extend the size of the stack segment. (This cannot happen if the stack was extended before it was locked.) Minimizing Interrupt Response Time You can ensure interrupt response time of 30 usecs or less for one specified device interrupt on a given CPU provided that you configure the system as follows: • The CPU does not receive any other SN hub device interrupts • The interrupt is handled by a device driver from a source that promises negligible processing time • The CPU is isolated from the effects of load balancing 007–4746–014 51 4: CPU Workload • The CPU is restricted from executing general Linux processes • Any process you assign to the CPU avoids system calls other than interprocess communication and allocation within an arena • Kernel module insertion and removal is avoided When these things are done, interrupts are serviced in minimal time. 52 007–4746–014 Chapter 5 Using the Frame Scheduler The frame scheduler makes it easy to structure a real-time program as a family of independent, cooperating activities that are running on multiple CPUs and are scheduled in sequence at the frame rate of the application. Note: With third-party x86-64 and Altix UV 10 architecture, the CC clock source is supplied by the PCI-RT-Z card. HUB hardware timers are not available on third-party x86-64 and Altix UV 10 platforms. On these platforms, you must have one PCI-RT-Z card per asynchronous frame scheduler. Multiple frame schedulers running synchronously can use a single PCI-RT-Z card, however. This chapter discusses the following: • "Frame Scheduler Concepts" on page 53 • "Selecting a Time Base" on page 69 • "Using the Scheduling Disciplines" on page 71 • "Using Multiple Consecutive Minor Frames" on page 73 • "Designing an Application for the Frame Scheduler" on page 75 • "Preparing the System" on page 76 • "Implementing a Single Frame Scheduler" on page 77 • "Implementing Synchronized Schedulers" on page 78 • "Handling Frame Scheduler Exceptions" on page 81 • "Using Signals Under the Frame Scheduler" on page 86 • "Using Timers with the Frame Scheduler" on page 89 Frame Scheduler Concepts One frame scheduler dispatches selected threads at a real-time rate on one CPU. You can also create multiple, synchronized frame schedulers that dispatch concurrent threads on multiple CPUs. 007–4746–014 53 5: Using the Frame Scheduler This section discusses the following: • "Frame Scheduler Basics" on page 54 • "Thread Programming Model" on page 55 • "Frame Scheduling" on page 55 • "Controller Thread" on page 58 • "Frame Scheduler API" on page 58 • "Interrupt Information Templates" on page 59 • "Library Interface for C Programs" on page 60 • "Thread Execution" on page 62 • "Scheduling Within a Minor Frame" on page 64 • "Synchronizing Multiple Schedulers" on page 66 • "Starting a Single Scheduler" on page 66 • "Starting Multiple Schedulers" on page 67 • "Pausing Frame Schedulers" on page 67 • "Managing Activity Threads" on page 68 Frame Scheduler Basics When a frame scheduler dispatches threads on one CPU, it does not completely supersede the operation of the normal Linux scheduler. The CPUs chosen for frame scheduling must be restricted and isolated (see "Restrict, Isolate, and Shield CPUs" on page 44). You do not have to set up cpusets for the frame-scheduled CPUs because the frame scheduler will set up cpusets named rtcpuN (where N is the CPU number) if this has not already been done. For more control over cpuset parameters, you can create your own cpusets for the frame scheduler to use (one per CPU, and one CPU per cpuset), by naming them exactly as mentioned above. If you already have cpusets named rtcpuN but they include other than only the CPU number in question, the frame scheduler will return an EEXIST error. 54 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Note: REACT for Linux does not support Vsync, device-driver, or system-call time bases. For more information, see "Preparing the System" on page 76. Thread Programming Model The frame scheduler supports pthreads. In this guide, a thread is defined as an independent flow of execution that consists of a set of registers (including a program counter and a stack). A pthread is defined by the POSIX standard. Pthreads within a process use the same global address space. A traditional Linux process has a single active thread that starts after the program is executed and runs until the program terminates. A multithreaded process may have several threads active at one time. Hence, a process can be viewed as a receptacle that contains the threads of execution and the resources they share (that is, data segments, text segments, file descriptors, synchronizers, and so forth). Frame Scheduling Instead of scheduling threads according to priorities, the frame scheduler dispatches them according to a strict, cyclic rotation governed by a repetitive time base. The time base determines the fundamental frame rate. (See "Selecting a Time Base" on page 69.) Some examples of the time base are as follows: • A specific clocked interval in microseconds • An external interrupt (see "External Interrupts as a Time Base" on page 70) • The Vsync (vertical retrace) interrupt from the graphics subsystem • A device interrupt from a specially modified device driver • A system call (normally used for debugging) Note: REACT for Linux does not support Vsync, device-driver, or system-call time bases. 007–4746–014 55 5: Using the Frame Scheduler The interrupts from the time base define minor frames. Together, a fixed number of minor frames make up a major frame. The length of a major frame defines the application’s true frame rate. The minor frames allow you to divide a major frame into subframes. Figure 5-1 shows major and minor frames. Major frame Minor-0 Minor-1 Major frame Minor-2 Minor-0 Minor-1 Minor-2 TIME Real-time event interrupts Thread queues Q0 Q1 Q2 Figure 5-1 Major and Minor Frames In the simplest case, there is a single frame rate, such as 60 Hz, and every activity the program performs must be done once per frame. In this case, the major and minor frame rates are the same. In other cases, there are some activities that must be done in every minor frame, but there are also activities that are done less often, such as in every other minor frame or in every third one. In these cases, you define the major frame so that its rate is the rate of the least-frequent activity. The major frame contains as many minor frames as necessary to schedule activities at their relative rates. As pictured in Figure 5-1, the frame scheduler maintains a queue of threads for each minor frame. You must queue each activity thread of the program to a specific minor frame. You determine the order of cyclic execution within a minor frame by the order in which you queue threads. You can do the following: • Queue multiple threads in one minor frame. They are run in the queued sequence within the frame. All must complete their work within the minor frame interval. 56 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide • Queue the same thread to run in more than one minor frame. For example, suppose that thread double is to run twice as often as thread solo. You would queue double to Q0 and Q2 in Figure 5-1, and queue solo to Q1. • Queue a thread that takes more than a minor frame to complete its work. If thread sloth needs more than one minor interval, you would queue it to Q0, Q1, and Q2, such that it can continue working in all three minor frames until it completes. • Queue a background thread that is allowed to run only when all others have completed, to use up any remaining time within a minor frame. All of these options are controlled by scheduling disciplines you specify for each thread as you queue it. For more information, see "Using the Scheduling Disciplines" on page 71. Typically, a frame scheduler is driven by a single interrupt source and contains minor frames having the same duration, but a variable frame scheduler may be used to implement a frame scheduler having multiple interrupt sources and/or minor frames of variable duration. For more information, see the frs_create_vmaster() function. The relationship between threads and a frame scheduler depends upon the thread model in use: • The pthread programming model requires that all threads scheduled by the frame scheduler reside in the same process. • The fork() programming model does not require that the participating threads reside in the same process. See "Implementing a Single Frame Scheduler" on page 77 for details. 007–4746–014 57 5: Using the Frame Scheduler Controller Thread The thread that creates a frame scheduler is called the frame scheduler controller thread. It is privileged in these respects: • Its identifier is used to identify its frame scheduler in various functions. The frame scheduler controller thread uses a pthread ID. • It can receive signals when errors are detected by the frame scheduler (see "Using Signals Under the Frame Scheduler" on page 86). • It cannot itself be queued to the frame scheduler. It continues to be dispatched by Linux and executes on a CPU other than the one that the frame scheduler uses. Frame Scheduler API For an overview of the frame scheduler API, see the frs(3) man page, which provides a complete listing of all the frame scheduler functions. Separate man pages for each of the frame scheduler functions provide the API details. The API elements are declared in /usr/include/frs.h. Table 5-1 shows some important types that are declared in /usr/include/frs.h. Table 5-1 Frame Scheduler Types 58 Type Description typedef frs_fsched_info_t A structure containing information about one scheduler (including its CPU number, interrupt source, and time base) and number of minor frames. Used when creating a frame scheduler. typedef frs_t A structure that identifies a frame scheduler. typedef frs_queue_info_t A structure containing information about one activity thread: the frame scheduler and minor frame it uses and its scheduling discipline. Used when enqueuing a thread. 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Type Description typedef frs_recv_info_t A structure containing error recovery options. typedef frs_intr_info_t A structure that frs_create_vmaster() uses for defining interrupt information templates (see Table 5-3 on page 60). Additionally, the pthreads interface adds the following types, as declared in /usr/include/sys/pthread.h: Table 5-2 Pthread Types Type Description typedef pthread_t An integer identifying the pthread ID. typedef pthread_attr_t A structure containing information about the attributes of the frame scheduler controller thread. Interrupt Information Templates Variable frame schedulers may drive each minor frame with a different interrupt source, as well as define a different duration for each minor frame. These two characteristics may be used together or separately, and are defined using an interrupt information template. An interrupt information template consists of an array of frs_intr_info_t data structures, where each element in the array represents a minor frame. For example, the first element in the array represents the interrupt information for the first minor frame, and so on for n minor frames. The frs_intr_info_t data structure contains two fields for defining the interrupt source and its qualifier: intr_source and intr_qualifier. The following example demonstrates how to define an interrupt information template for a frame scheduler having minor frames of different duration. Assume the application requires four minor frames, where each minor frame is triggered by the synchronized clock timer, and the duration of each minor frame is as follows: 100 ms, 150 ms, 200 ms, and 250 ms. 007–4746–014 59 5: Using the Frame Scheduler The interrupt information template may be defined as follows: frs_intr_info_t intr_info[4]; intr_info[0].intr_source = intr_info[0].intr_qualifier = intr_info[1].intr_source = intr_info[1].intr_qualifier = intr_info[2].intr_source = intr_info[2].intr_qualifier = intr_info[3].intr_source = intr_info[3].intr_qualifier = FRS_INTRSOURCE_CCTIMER; 100000; FRS_INTRSOURCE_CCTIMER; 150000; FRS_INTRSOURCE_CCTIMER; 200000; FRS_INTRSOURCE_CCTIMER; 250000; For detailed programming examples, demonstrating the use of variable frame schedulers, see the /usr/share/react/frs/examples directory and the frs_create_vmaster(3) man page. Library Interface for C Programs Table 5-3 summarizes the API library functions in the /usr/lib/libfrs.a file. Table 5-3 Frame Scheduler Operations Operation Use Frame Scheduler API Create a frame scheduler Process setup frs_t* frs_create(cpu, (int int intr_source int intr_qualifier, int, n_minors, pid_t sync_master_pid, intnum_slaves); Process or pthread setup frs_t* frs_create_master(int cpu, int intr_source, int intr_qualifier, int n_minors, int num_slaves); Process or pthread setup frs_t* frs_create_slave(int cpu, frs_t* sync_master_frs); Process or pthread setup frs_t* frs_create_vmaster(int cpu, int n_minors, int n_slaves, frs_intr_info_t *intr_info); Process setup int frs_enqueue(frs_t* frs, pid_t pid, int minor_frame, unsigned int discipline); Queue to a frame scheduler minor frame 60 007–4746–014 TM REACT Operation Insert into a queue, possibly changing discipline Set error recovery options Join a frame scheduler (activity is ready to start) Real-Time for Linux® Programmer’s Guide Use Frame Scheduler API Pthread setup int frs_pthread_enqueue(frs_t* frs, pthread_t pthread, int minor_frame, unsigned int discipline); Process setup int frs_pinsert(frs_t* frs, int minor_frame, pid_t target_pid, int discipline, pid_t base_pid); Pthread setup int frs_pthread_insert(frs_t* frs, int minor_index, pthread_t target_pthread, int discipline, pthread_t base_pthread); Process setup int frs_setattr(frs_t* frs, int minor_frame, pid_t pid, frs_attr_t attribute, void* param); Pthread setup int frs_pthread_setattr(frs_t* frs, int minor_frame, pthread_t pthread, frs_attr_t attribute, void* param); Process or pthread execution int frs_join(frs_t* frs); Start scheduling (all Process or pthread activities queued) execution int frs_start(frs_t* frs); Yield control after completing activity int frs_yield(void); Process or pthread execution Pause scheduling at Process or pthread end of minor frame execution int frs_stop(frs_t* frs); Resume scheduling at next time-base interrupt Process or pthread execution int frs_resume(frs_t* frs); Trigger a user-level frame scheduler interrupt Process or pthread execution int frs_userintr(frs_t* frs); Interrogate a minor frame queue Process or pthread query int frs_getqueuelen(frs_t* frs, int minor_index); Process query int frs_readqueue(frs_t* frs, int minor_frame, pid_t *pidlist); Pthread query int frs_pthread_readqueue(frs_t* frs, int minor_frame, pthread_t *pthreadlist); 007–4746–014 61 5: Using the Frame Scheduler Operation Use Frame Scheduler API Retrieve error recovery options Process query int frs_getattr(frs_t* frs, int minor_frame, pid_t pid, frs_attr_t attribute, void* param); Pthread query int frs_pthread_getattr(frs_t* frs, int minor_frame, pthread_t pthread, frs_attr_t attribute, void* param); Destroy frame scheduler and send SIGKILL to its frame scheduler controller Process or pthread teardown int frs_destroy(frs_t* frs); Remove a process or thread from a queue Process teardown int frs_premove(frs_t* frs, int minor_frame, pid_t remove_pid); Pthread teardown int frs_pthread_remove(frs_t* frs, int minor_frame, pthread_t remove_pthread); Pthread setup int frs_pthread_register(void); Register a thread Thread Execution Example 5-1 shows the basic structure of an activity thread that is queued to a frame scheduler. Example 5-1 Skeleton of an Activity Thread /* Initialize data structures etc. */ frs_join(scheduler-handle) do { /* Perform the activity. */ frs_yield(); } while(1); _exit(); When the thread is ready to start real-time execution, it calls frs_join(). This call blocks until all queued threads are ready and scheduling begins. When frs_join() returns, the thread is running in its first minor frame. For more information, see "Starting Multiple Schedulers" on page 67 and the frs_join(3) man page. 62 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Note: Each thread of a pthreaded application (including the controller thread) must first call frs_pthread_register() before making any other calls to the frame scheduler. In addition, each activity thread must complete its call to frs_pthread_register before the controller thread calls frs_pthread_enqueue. The thread then performs whatever activity is needed to complete the minor frame and calls frs_yield(). This gives up control of the CPU until the next minor frame where the thread is queued and executes. For more information, see the frs_yield(3) man page. An activity thread is never preempted by the frame scheduler within a minor frame. As long as it yields before the end of the frame, it can do its assigned work without interruption from other activity threads. (However, it can be interrupted by hardware interrupts, if they are allowed in that CPU.) The frame scheduler preempts the thread at the end of the minor frame. When a very short minor frame interval is used, it is possible for a thread to have an overrun error in its first frame due to cache misses. A simple variation on the basic structure shown in Example 5-1 is to spend the first minor frame touching a set of important data structures in order to “warm up” the cache. This is sketched in Example 5-2. Example 5-2 Alternate Skeleton of an Activity Thread /* Initialize data structures etc. */ frs_join(scheduler-handle); /* Much time could pass here. */ /* First frame: merely touch important data structures. */ do { frs_yield(); /* Second and later frames: perform the activity. */ } while(1); _exit(); When an activity thread is scheduled on more than one minor frame in a major frame, it can be designed to do nothing except warm up the cache in the entire first major frame. To do this, the activity thread function must know how many minor frames it is scheduled on and call frs_yield() a corresponding number of times in order to pass the first major frame. 007–4746–014 63 5: Using the Frame Scheduler Scheduling Within a Minor Frame Threads in a minor frame queue are dispatched in the order that they appear on the queue (priority is irrelevant). Queue ordering can be modified as follows: • Appending a thread at the end of the queue with frs_pthread_enqueue() or frs_enqueue() • Inserting a thread after a specific target thread via frs_pthread_insert() or frs_pinsert() • Deleting a thread in the queue with frs_pthread_remove() or frs_premove() See "Managing Activity Threads" on page 68 and the frs_enqueue(3), frs_pinsert(3), and frs_premove(3) man pages. Scheduler Flags frs_run and frs_yield The frame scheduler keeps two status flags per queued thread: frs_run and frs_yield: • If a thread is ready to run when its turn comes, it is dispatched and its frs_run flag is set to indicate that this thread has run at least once within this minor frame. • When a thread yields, its frs_yield flag is set to indicate that the thread has released the processor. It is not activated again within this minor frame. If a thread is not ready (usually because it is blocked waiting for I/O, a semaphore, or a lock), it is skipped. Upon reaching the end of the queue, the scheduler goes back to the beginning, in a round-robin fashion, searching for threads that have not yielded and may have become ready to run. If no ready threads are found, the frame scheduler goes into idle mode until a thread becomes available or until an interrupt marks the end of the frame. Detecting Overrun and Underrun When a time base interrupt occurs to indicate the end of the minor frame, the frame scheduler checks the flags for each thread. If the frs_run flag has not been set, that thread never ran and therefore is a candidate for an underrun exception. If the frs_run flag is set but the frs_yield flag is not, the thread is a candidate for an overrun exception. 64 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Whether these exceptions are declared depends on the scheduling discipline assigned to the thread. For more information, see "Using the Scheduling Disciplines" on page 71. At the end of a minor frame, the frame scheduler resets all frs_run flags, except for those of threads that use the continuable discipline in that minor frame. For those threads, the residual frs_yield flags keeps the threads that have yielded from being dispatched in the next minor frame. Underrun and overrun exceptions are typically communicated via Linux signals. For more information, see "Using Signals Under the Frame Scheduler" on page 86. Estimating Available Time It is up to the application to make sure that all the threads queued to any minor frame can actually complete their work in one minor-frame interval. If there is too much work for the available CPU cycles, overrun errors will occur. Estimation is somewhat simplified by the fact that a restricted CPU will only execute threads specifically pinned to it, along with a few CPU-specific kernel threads. You must estimate the maximum time each thread can consume between one call to frs_yield() and the next. Frame scheduler threads do compete for CPU cycles with I/O interrupts on the same CPU. If you direct I/O interrupts away from the CPU, the only competition for CPU cycles (other than a very few essential interrupts and CPU-specific kernel threads) is the overhead of the frame scheduler itself, and it has been carefully optimized to reduce overhead. Alternatively, you may assign specific I/O interrupts to a CPU used by the frame scheduler. In that case, you must estimate the time that interrupt service will consume and allow for it. 007–4746–014 65 5: Using the Frame Scheduler Synchronizing Multiple Schedulers When the activities of one frame cannot be completed by one CPU, you must recruit additional CPUs and execute some activities concurrently. However, it is important that each of the CPUs have the same time base, so that each starts and ends frames at the same time. You can create one master frame scheduler that owns the time base and one CPU, and as many synchronized (slave) frame schedulers as you need, each managing an additional CPU. The slave schedulers take their time base from the master, so that all start minor frames at the same instant. Each frame scheduler requires its own controller thread. Therefore, to create multiple, synchronized frame schedulers, you must create a controller thread for the master and each slave frame scheduler. Each frame scheduler has its own queues of threads. A given thread can be queued to only one CPU. (However, you can create multiple threads based on the same code, and queue each to a different CPU.) All synchronized frame schedulers use the same number of minor frames per major frame, which is taken from the definition of the master frame scheduler. Starting a Single Scheduler A single frame scheduler is created when the frame scheduler controller thread calls frs_create_master() or frs_create(). The frame scheduler controller calls frs_pthread_enqueue() or frs_enqueue() one or more times to notify the new frame scheduler of the threads to schedule in each of the minor frames. The frame scheduler controller calls frs_start() when it has queued all the threads. Each scheduled thread must call frs_join() after it has initialized and is ready to be scheduled. Each activity thread must be queued to at least one minor frame before it can join the frame scheduler via frs_join(). After all threads have called frs_join() and the controller has called frs_start(), scheduling of worker threads in the first minor frame occurs after the second interrupt arrives. Note: The first interrupt is used to drive the frame scheduler’s internal processing during which time no scheduling occurs. 66 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide For more information about these functions, see the frs_enqueue(3), frs_join(3), and frs_start(3) man pages. Starting Multiple Schedulers A frame scheduler cannot start dispatching activities until the following have occurred: • The frame scheduler controller has queued all the activity threads to their minor frames • All the queued threads have done their own initial setup and have called frs_join. When multiple frame schedulers are used, none can start until all are ready. Each frame scheduler controller notifies its frame scheduler that it has queued all activities by calling frs_start(). Each activity thread signals its frame scheduler that it is ready to begin real-time processing by calling frs_join(). A frame scheduler is ready when it has received one or more frs_pthread_enqueue() or frs_enqueue() calls, a matching number of frs_join() calls, and an frs_start() call for each frame scheduler. Each slave frame scheduler notifies the master frame scheduler when it is ready. When all the schedulers are ready, the master frame scheduler gives the downbeat and the first minor frame begins. Note: After all threads have called frs_join() and the controller has called frs_start(), scheduling of worker threads in the first minor frame does not occur until the second interrupt arrives. The first interrupt is used to drive the frame scheduler’s internal processing during which time no scheduling occurs. Pausing Frame Schedulers Any frame scheduler can be made to pause and restart. Any thread (typically but not necessarily the frame scheduler controller) can call frs_stop(), specifying a particular frame scheduler. That scheduler continues dispatching threads from the current minor frame until all have yielded. Then it goes into an idle loop until a call to frs_resume() tells it to start. It resumes on the next time-base interrupt, with the 007–4746–014 67 5: Using the Frame Scheduler next minor frame in succession. For more information, see the frs_stop(3) and frs_resume(3) man pages. Note: If there is a thread running background discipline in the current minor frame, it continues to execute until it yields or is blocked on a system service. See "Background Discipline" on page 73. Because a frame scheduler does not stop until the end of a minor frame, you can stop and restart a group of synchronized frame schedulers by calling frs_stop() for each one before the end of a minor frame. There is no way to restart all of a group of schedulers with the certainty that they start up on the same time-base interrupt. Managing Activity Threads The frame scheduler controller identifies the initial set of activity threads by calling frs_pthread_enqueue() or frs_enqueue() prior to starting the frame scheduler. All the queued threads must call frs_join() before scheduling can begin. However, the frame scheduler controller can change the set of activity threads dynamically while the frame scheduler is working, using the functions shown in Table 5-4 on page 68. Table 5-4 Activity Thread Functions Function Description frs_getqueuelen() Gets the number of threads currently in the queue for a specified minor frame frs_pthread_readqueue() or frs_readqueue() Returns the ID values of all queued threads for a specified minor frame as a vector of integers frs_pthread_remove() or frs_premove() Removes a thread (specified by its ID) from a minor frame queue frs_pthread_insert() or frs_pinsert() Inserts a thread (specified by its ID and discipline) into a given position in a minor frame queue Using these functions, the frame scheduler controller can change the queueing discipline (overrun, underrun, continuable) of a thread by removing it and inserting it 68 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide with a new discipline. The frame scheduler controller can suspend a thread by removing it from its queue or can restart a thread by putting it back in its queue. Note: When an activity thread is removed from the last or only queue it was in, it no longer is dispatched by the frame scheduler. When an activity thread is removed from a queue, a signal may be sent to the removed thread (see "Handling Signals in an Activity Thread" on page 87). If a signal is sent to it, it begins executing in its specified or default signal handler; otherwise, it begins executing following frs_yield(). After being returned to the Linux scheduler, a call to a frame scheduler function such as frs_yield() returns an error (this also can be used to indicate the resumption of normal scheduling). The frame scheduler controller can also queue new threads that have not been scheduled before. The frame scheduler does not reject an frs_pthread_insert() or frs_pinsert() call for a thread that has not yet joined the scheduler. However, a thread must call frs_join() before it can be scheduled. For more information, see the frs_pinsert(3) man page. If a queued thread is terminated for any reason, the frame scheduler removes the thread from all queues in which it appears. Selecting a Time Base The program specifies an interrupt source for the time base when it creates the master (or only) frame scheduler. The master frame scheduler initializes the necessary hardware resources and redirects the interrupt to the appropriate CPU and handler. The frame scheduler time base is fundamental because it determines the duration of a minor frame, and hence the frame rate of the program. This section explains the different time bases that are available. When you use multiple, synchronized frame schedulers, the master frame scheduler distributes the time-base interrupt to each synchronized CPU. This ensures that minor-frame boundaries are synchronized across all the frame schedulers. This section discusses the following: • "High-Resolution Timer" on page 70 • "External Interrupts as a Time Base" on page 70 007–4746–014 69 5: Using the Frame Scheduler High-Resolution Timer The real-time clock (RTC) is synchronous across all processors and is ideal to drive synchronous schedulers. REACT uses the RTC for its frame scheduler high-resolution timer solution. Note: Frame scheduler applications cannot use POSIX high-resolution timers. To use the RTC, specify FRS_INTRSOURCE_CCTIMER and the minor frame interval in microseconds to frs_create_master() or frs_create(). The maximum frame rate supported by a timer is 2000 Hz. The high-resolution timers in all CPUs are synchronized automatically. Note: Third-party x86-64 and Altix UV 10 servers do not have a HUB RTC timer. A PCI-RT-Z external interrupt card is supplied by SGI and is required for generation of the Frame Scheduler cc-timer interrupts. Each PCI-RT-Z card can generate interrupts at one set frequency, so a PCI-RT-Z card is required for each asynchronous frame scheduler running on a system. External Interrupts as a Time Base To use external interrupts as a time base, do the following: 1. Load ioc4_extint to load the external interrupts modules. 2. Open the appropriate external interrupts device file. For example: if ((fd = open("/dev/extint0", O_RDONLY)) < 0) { perror("Open EI control file"); return 1; } 3. Specify FRS_INTRSOURCE_EXTINTR as the intr_source and pass the returned file descriptor as the intr_qualifier to frs_create_master or frs_create. The CPU receiving the interrupt allocates it simultaneously to the synchronized schedulers. If other IOC4 devices are also in use, you should redirect IOC4 interrupts to a non-frame-scheduled CPU in order to avoid jitter and delay. 70 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Note: After all threads have called frs_join() and the controller has called frs_start(), scheduling of worker threads in the first minor frame does not occur until the second interrupt arrives. The first interrupt is used to drive the frame scheduler’s internal processing during which time no scheduling occurs. For more information, see Chapter 3, "External Interrupts" on page 17. Using the Scheduling Disciplines When a frame scheduler controller thread queues an activity thread to a minor frame using frs_pthread_enqueue() or frs_enqueue(), it must specify a scheduling discipline that tells the frame scheduler how the thread is expected to use its time within that minor frame. The disciplines are as follows: • "Real-Time Discipline" on page 71 • "Underrunable Discipline" on page 72 • "Overrunnable Discipline" on page 72 • "Continuable Discipline" on page 73 • "Background Discipline" on page 73 Real-Time Discipline In the real-time discipline, an activity thread starts during the minor frame in which it is queued, completes its work, and yields within the same minor frame. If the thread is not ready to run (for example, if it is blocked on I/O) during the entire minor frame, an underrun exception is said to occur. If the thread fails to complete its work and yield within the minor frame interval, an overrun exception is said to occur. Note: If an activity thread becomes blocked by other than an frs_yield() call (and therefore is not ready to run) and later becomes unblocked outside of its minor frame slot, it will run assuming that no other threads are available to run (similar to "Background Discipline" on page 73) until it yields or a new minor frame begins. 007–4746–014 71 5: Using the Frame Scheduler This model could describe a simple kind of simulator in which certain activities (such as poll the inputs, calculate the new status, and update the display) must be repeated in the same order during every frame. In this scenario, each activity must start and must finish in every frame. If one fails to start, or fails to finish, the real-time program is broken and must take action. However, realistic designs need the flexibility to have threads with the following characteristics: • Need not start every frame; for instance, threads that sleep on a semaphore until there is work for them to do • May run longer than one minor frame • Should run only when time is available, and whose rate of progress is not critical The other disciplines are used, in combination with real-time and with each other, to allow these variations. Underrunable Discipline You specify the underrunable discipline in the following cases: • When a thread needs to run only when an event has occurred, such as a lock being released or a semaphore being posted • When a thread may need more than one minor frame (see "Using Multiple Consecutive Minor Frames" on page 73) To prevent detection of underrun exceptions, specify the underrunable discipline with the real-time discipline. When you specify real-time plus underrunable, the thread is not required to start in that minor frame. However, if it starts, it is required to yield before the end of the frame or an overrun exception is raised. Overrunnable Discipline You specify the overrunnable discipline in the following cases: • When it truly does not matter if the thread fails to complete its work within the minor frame—for example, a calculation of a game strategy that, if it fails to finish, merely makes the computer a less dangerous opponent 72 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide • When a thread may need more than one minor frame (see "Using Multiple Consecutive Minor Frames" on page 73) To prevent detection of overrun exceptions, specify an overrunnable discipline with a real-time discipline. When you specify overrunnable plus real-time, the thread is not required to call frs_yield() before the end of the frame. Even so, the thread is preempted at the end of the frame. It does not have a chance to run again until the next minor frame in which it is queued. At that time it resumes where it was preempted, with no indication that it was preempted. Continuable Discipline You specify continuable discipline with real-time discipline to prevent the frame scheduler from clearing the flags at the end of this minor frame (see "Scheduling Within a Minor Frame" on page 64). The result is that, if the thread yields in this frame, it need not run or yield in the following frame. The residual frs_yield flag value, carried forward to the next frame, applies. You specify continuable discipline with other disciplines in order to let a thread execute just once in a block of consecutive minor frames. Background Discipline The background discipline is mutually exclusive with the other disciplines. The frame scheduler dispatches a background thread only when all other threads queued to that minor frame have run and have yielded. Because the background thread cannot be sure it will run and cannot predict how much time it will have, the concepts of underrun and overrun do not apply to it. Note: A thread with the background discipline must be queued to its frame following all non-background threads. Do not queue a real-time thread after a background thread. Using Multiple Consecutive Minor Frames There are cases when a thread sometimes or always requires more than one minor frame to complete its work. Possibly the work is lengthy, or possibly the thread could be delayed by a system call or a lock or semaphore wait. 007–4746–014 73 5: Using the Frame Scheduler You must decide the absolute maximum time the thread could consume between starting up and calling frs_yield(). If this is unpredictable, or if it is predictably longer than the major frame, the thread cannot be scheduled by the frame scheduler. Hence, it should probably run on another CPU under the Linux real-time scheduler. However, when the worst-case time is bounded and is less than the major frame, you can queue the thread to enough consecutive minor frames to allow it to finish. A combination of disciplines is used in these frames to ensure that the thread starts when it should, finishes when it must, and does not cause an error if it finishes early. The discipline settings should be as follows: Frame Description First Real-time + overrunnable + continuable The thread must start in this frame (not underrunable) but is not required to yield (overrunnable). If it yields, it is not restarted in the following minor frame (continuable). Intermediate Realtime + underrunable + overrunnable + continuable The thread need not start (it might already have yielded, or might be blocked) but is not required to yield. If it does yield or if it had yielded in a preceding minor frame, it is not restarted in the following minor frame (continuable). Final Realtime + underrunable The thread need not start (it might already have yielded) but if it starts, it must yield in this frame (not overrunnable). The thread can start a new run in the next minor frame to which it is queued (not continuable). A thread can be queued for one or more of these multiframe sequences in one major frame. For example, suppose that the minor frame rate is 60 Hz and a major frame contains 60 minor frames (1 Hz). You have a thread that should run at a rate of 5 Hz and can use up to 3/60 second at each dispatch. You can queue the thread to 5 sequences of 3 consecutive frames each. It could start in frames 0, 12, 24, 36, and 48. Frames 1, 13, 25, 37, and 49 could be intermediate frames, and 2, 14, 26, 38, and 50 could be final frames. 74 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Designing an Application for the Frame Scheduler When using the frame scheduler, consider the following guidelines when designing a real-time application: 1. Determine the programming model for implementing the activities in the program, choosing between POSIX threads or SVR4 fork() calls. (You cannot mix pthreads and other disciplines within the program.) 2. Partition the program into activities, where each activity is an independent piece of work that can be done without interruption. For example, in a simple vehicle simulator, activities might include the following: • Poll the joystick • Update the positions of moving objects • Cull the set of visible objects 3. Decide the relationships among the activities, as follows: • Some must be done once per minor frame, others less frequently • Some must be done before or after others • Some may be conditional (for example, an activity could poll a semaphore and do nothing unless an event had completed) 4. Estimate the worst-case time required to execute each activity. Some activities may need more than one minor frame interval (the frame scheduler allows for this). 5. Schedule the activities. If all are executed sequentially, will they complete in one major frame? If not, choose activities that can execute concurrently on two or more CPUs, and estimate again. You may have to change the design in order to get greater concurrency. When the design is complete, implement each activity as an independent thread that communicates with the others using shared memory, semaphores, and locks. A controller thread creates, stops, and resumes the frame scheduler. The controller thread can also interrogate and receive signals from the frame scheduler. A frame scheduler seizes its assigned CPU, isolates it, and controls the scheduling on it. It waits for all queued threads to initialize themselves and join the scheduler. The frame scheduler begins dispatching the threads in the specified sequence during each 007–4746–014 75 5: Using the Frame Scheduler frame interval. Errors are monitored (such as a thread that fails to complete its work within its frame) and a specified action is taken when an error occurs. Typically, the error action is to send a signal to the controller thread. Preparing the System Before a real-time program executes, you must do the following: 1. Choose the CPUs that the real-time program will use. CPU 0 (at least) must be reserved for Linux system functions. 2. Decide which CPUs will handle I/O interrupts. By default, Linux distributes I/O interrupts across all available processors as a means of balancing the load (referred to as spraying interrupts). You should redirect I/O interrupts away from CPUs that are used for real-time programs. For more information, see "Redirect Interrupts" on page 43. 3. If you are using an external interrupt as a time base, make sure it is redirected to the CPU of the master frame scheduler. For more information, see "External Interrupts as a Time Base" on page 70. 4. Make sure that none of the real-time CPUs is managing the clock. Normally, the responsibility of handling 10–ms scheduler interrupts is given to CPU 0. For more information, see "Avoid the Clock Processor (CPU 0)" on page 43. 5. Restrict and isolate the real-time CPUs, as described in "Restrict, Isolate, and Shield CPUs" on page 44. 6. Load the frs kernel module: [root@linux root]# modprobe frs Note: You must perform this step after each system boot. 7. If you are using external interrupts as a time base or if you are running the frame scheduler on a third-party x86-64 or Altix UV 10 server, you must load the ioc4_extint kernel module: [root@linux root]# modprobe ioc4_extint 76 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Implementing a Single Frame Scheduler When the activities of a real-time program can be handled within a major frame interval by a single CPU, the program requires only one frame scheduler. The programs found in /usr/share/react/frs/examples provide examples of implementing a single frame scheduler. Typically, a program has a top-level controller thread to handle startup and termination, and one or more activity threads that are dispatched by the frame scheduler. The activity threads are typically lightweight pthreads, but that is not a requirement; they can also be created with fork(). (They need not be children of the controller thread.) For examples, see /usr/share/react/frs/examples. In general, these are the steps for setting up a single frame scheduler: 1. Initialize global resources such as memory-mapped segments, memory arenas, files, asynchronous I/O, semaphores, locks, and other resources. 2. Lock the shared address space segments. (When fork() is used, each child process must lock its own address space.) 3. If using pthreads, create a controller thread; otherwise, the initial thread of execution may be used as the controller thread. • Create a controller thread using pthread_create() and the attribute structure you just set up. See the pthread_create(3P) man page for details. • Exit the initial thread, because it cannot execute any frame scheduler operations. 4. Create the frame scheduler using frs_create_master(), frs_create_vmaster(), or frs_create(). See the frs_create(3) man page. 007–4746–014 77 5: Using the Frame Scheduler 5. Create the activity threads using one of the following interfaces, depending on the thread model being used: • pthread_create() • fork() 6. Queue the activity threads on the target minor frame queues, using frs_pthread_enqueue() or frs_enqueue(). 7. Optionally, initialize the frame scheduler signal handler to catch frame overrun, underrun, and activity dequeue events (see "Setting Frame Scheduler Signals" on page 87 and "Setting Exception Policies" on page 83). The handlers are set at this time, after creation of the activity threads, so that the activity threads do not inherit them. 8. Use frs_start() to enable scheduling. For more information, see Table 5-3 on page 60. 9. Have the activity threads call frs_join(). The frame scheduler begins scheduling processes as soon as all the activity threads have called frs_join(). 10. Wait for error signals from the frame scheduler and for the termination of child processes. 11. Use frs_destroy() to terminate the frame scheduler. 12. Perform program cleanup as desired. See /usr/share/react/frs/examples. Implementing Synchronized Schedulers When the real-time application requires the power of multiple CPUs, you must add one more level to the program design for a single CPU. The program creates multiple frame schedulers, one master and one or more synchronized slaves. 78 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide This section discusses the following: • "Synchronized Scheduler Concepts" on page 79 • "Master Controller Thread" on page 79 • "Slave Controller Thread" on page 80 Synchronized Scheduler Concepts The first frame scheduler provides the time base for the others. It is called the master scheduler. The other schedulers take their time base interrupts from the master, and so are called slaves. The combination is called a sync group. No single thread may create more than one frame scheduler. This is because every frame scheduler must have a unique frame scheduler controller thread to which it can send signals. As a result, the program has the following types of threads: • A master controller thread that sets up global data and creates the master frame scheduler • One slave controller thread for each slave frame scheduler • Activity threads The master frame scheduler must be created before any slave frame schedulers can be created. Slave frame schedulers must be specified to have the same time base and the same number of minor frames as the master. Slave frame schedulers can be stopped and restarted independently. However, when any scheduler (master or slave) is destroyed, all are immediately destroyed. Master Controller Thread The master controller thread performs these steps: 1. Initializes a global resource. One global resource is the thread ID of the master controller thread. 2. Creates the master frame scheduler using either the frs_create_master() or frs_create_vmaster() call and stores its handle in a global location. 3. Creates one slave controller thread for each synchronized CPU to be used. 007–4746–014 79 5: Using the Frame Scheduler 4. Creates the activity threads that will be scheduled by the master frame scheduler and queues them to their assigned minor frames. 5. Sets up signal handlers for signals from the frame scheduler. See "Using Signals Under the Frame Scheduler" on page 86. 6. Uses frs_start() to tell the master frame scheduler that its activity threads are all queued and ready to commence scheduling. See Table 5-3 on page 60. The master frame scheduler starts scheduling threads as soon as all threads have called frs_join() for their respective schedulers. 7. Waits for error signals. 8. Uses frs_destroy() to terminate the master frame scheduler. 9. Performs any desired program cleanup. Slave Controller Thread Each slave controller thread performs these steps: 1. Creates a synchronized frame scheduler using frs_create_slave(), specifying information about the master frame scheduler stored by the master controller thread. The master frame scheduler must exist. A slave frame scheduler must specify the same time base and number of minor frames as the master frame scheduler. 2. Changes the frame scheduler signals or exception policy, if desired. See "Setting Frame Scheduler Signals" on page 87 and "Setting Exception Policies" on page 83. 3. Creates the activity threads that are scheduled by this slave frame scheduler and queues them to their assigned minor frames. 4. Sets up signal handlers for signals from the slave frame scheduler. 5. Uses frs_start() to tell the slave frame scheduler that all activity threads have been queued. The slave frame scheduler notifies the master when all threads have called frs_join(). When the master frame scheduler starts broadcasting interrupts, scheduling begins. 6. Waits for error signals. 80 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide 7. Uses frs_destroy() to terminate the slave frame scheduler. For an example of this kind of program structure, refer to /usr/share/react/frs/examples. Tip: In this design sketch, the knowledge of which activity threads to create, and on which frames to queue them, is distributed throughout the code, where it might be hard to maintain. However, it is possible to centralize the plan of schedulers, activities, and frames in one or more arrays that are statically initialized. This improves the maintainability of a complex program. Handling Frame Scheduler Exceptions The frame scheduler controller manages overrun and underrun exceptions. It can specify how these exceptions should be handled and what signals the frame scheduler should send. These policies must be set before the scheduler is started. While the scheduler is running, the frame scheduler controller can query the number of exceptions that have occurred. This section discusses the following: • "Exception Types" on page 81 • "Exception Handling Policies" on page 82 • "Setting Exception Policies" on page 83 • "Querying Counts of Exceptions" on page 84 Exception Types The overrun exception indicates that a thread failed to yield in a minor frame where it was expected to yield and was preempted at the end of the frame. An overrun exception indicates that an unknown amount of work that should have been done was not done, and will not be done until the next frame in which the overrunning thread is queued. The underrun exception indicates that a thread that should have started in a minor frame did not start. The thread may have terminated or (more likely) it was blocked 007–4746–014 81 5: Using the Frame Scheduler in a wait because of an unexpected delay in I/O or because of a deadlock on a lock or semaphore. Exception Handling Policies The frame scheduler controller can establish one of four policies for handling overrun and underrun exceptions. When it detects an exception, the frame scheduler can do the following: • Send a signal to the controller • Inject an additional minor frame • Extend the frame by a specified number of microseconds • Steal a specified number of microseconds from the following frame By default, it sends a signal. The scheduler continues to run. The frame scheduler controller can then take action, such as terminating the frame scheduler. For more information, see "Setting Frame Scheduler Signals" on page 87. Injecting a Repeat Frame The policy of injecting an additional minor frame can be used with any time base. The frame scheduler inserts another complete minor frame, essentially repeating the minor frame in which the exception occurred. In the case of an overrun, the activity threads that did not finish have another frame’s worth of time to complete. In the case of an underrun, there is that much more time for the waiting thread to wake up. Because exactly one frame is inserted, all other threads remain synchronized to the time base. Extending the Current Frame The policies of extending the frame, either with more time or by stealing time from the next frame, are allowed only when the time base is a high-resolution timer. For more information, see "Selecting a Time Base" on page 69. When adding time, the current frame is made longer by a fixed amount of time. Because the minor frame becomes a variable length, it is possible for the frame scheduler to drop out of synchronization with an external device. When stealing time from the following frame, the frame scheduler returns to the original time base at the end of the following minor frame provided that the threads 82 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide queued to that following frame can finish their work in a reduced amount of time. If they do not, the frame scheduler steals time from the next frame. Dealing With Multiple Exceptions You decide how many consecutive exceptions are allowed within a single minor frame. After injecting, stretching, or stealing time that many times, the frame scheduler stops trying to recover and sends a signal instead. The count of exceptions is reset when a minor frame completes with no remaining exceptions. Setting Exception Policies The frs_pthread_setattr() or frs_setattr() function is used to change exception policies. This function must be called before the frame scheduler is started. After scheduling has begun, an attempt to change the policies or signals is rejected. In order to allow for future enhancements, frs_pthread_setattr() or frs_setattr() accepts arguments for minor frame number and thread ID; however it currently allows setting exception policies only for all policies and all minor frames. The most significant argument to it is the frs_recv_info structure, declared with the following fields: typedef struct frs_recv_info { mfbe_rmode_t rmode; /* mfbe_tmode_t tmode; /* uint maxcerr; /* uint xtime; /* } frs_recv_info_t; Basic recovery mode */ Time expansion mode */ Max consecutive errors */ Recovery extension time */ The recovery modes and other constants are declared in /usr/include/frs.h. The function in Example 5-3 sets the policy of injecting a repeat frame. The caller specifies only the frame scheduler and the number of consecutive exceptions allowed. 007–4746–014 83 5: Using the Frame Scheduler Example 5-3 Function to Set INJECTFRAME Exception Policy int setInjectFrameMode(frs_t *frs, int consecErrs) { frs_recv_info_t work; bzero((void*)&work,sizeof(work)); work.rmode = MFBERM_INJECTFRAME; work.maxcerr = consecErrs; return frs_setattr(frs,0,0,FRS_ATTR_RECOVERY,(void*)&work); } The function in Example 5-4 sets the policy of stretching the current frame (a function to set the policy of stealing time from the next frame is nearly identical). The caller specifies the frame scheduler, the number of consecutive exceptions, and the stretch time in microseconds. Example 5-4 Function to Set STRETCH Exception Policy int setStretchFrameMode(frs_t *frs,int consecErrs,uint microSecs) { frs_recv_info_t work; bzero((void*)&work,sizeof(work)); work.rmode = MFBERM_EXTENDFRAME_STRETCH; work.tmode = EFT_FIXED; /* only choice available */ work.maxcerr = consecErrs; work.xtime = microSecs; return frs_setattr(frs,0,0,FRS_ATTR_RECOVERY,(void*)&work); } Querying Counts of Exceptions When you set a policy that permits exceptions, the frame scheduler controller thread can query for counts of exceptions. This is done with a call to frs_pthread_getattr() or frs_getattr(), passing the handle to the frame scheduler, the number of the minor frame and the thread ID of the thread within that frame. The values returned in a structure of type frs_overrun_info_t are the counts of overrun and underrun exceptions incurred by that thread in that minor frame. In order to find the count of all overruns in a given minor frame, you must sum the 84 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide counts for all threads queued to that frame. If a thread is queued to more than one minor frame, separate counts are kept for it in each frame. The function in Example 5-5 takes a frame scheduler handle and a minor frame number. It gets the list of thread IDs queued to that minor frame, and returns the sum of all exceptions for all of them. Example 5-5 Function to Return a Sum of Exception Counts (pthread Model) #define THE_MOST_TIDS 250 int totalExcepts(frs_t * theFRS, int theMinor) { int numTids = frs_getqueuelen(theFRS, theMinor); int j, sum; pthread_t allTids[THE_MOST_TIDS]; if ( (numTids <= 0) || (numTids > THE_MOST_TIDS) ) return 0; /* invalid minor #, or no threads queued? */ if (frs_pthread_readqueue(theFRS, theMinor, allTids) == -1) return 0; /* unexpected problem with reading IDs */ for (sum = j = 0; j TAbort- TAbort- SERR- #include /* link with -lreact */ Example Code Using the REACT Library Routines Following is example code using the REACT library. /* Add, Delete and RunOn*/ int new_rtcpu = 3; if ((cpus = bitmask_alloc(cpuset_cpus_nbits())) == NULL) { perror("cpuset: bitmask alloc failed:"); exit (1); } bitmask_setbit(cpus, new_rtcpu); if (cpu_sysrt_add(cpus, RT_WAIT)){ 124 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide perror("cpu_sysrt_add failed:"); } if (cpu_sysrt_runon(new_rtcpu)) { perror("cpu_sysrt_runon"); exit(1); } .. /* RT CODE */ .. if (cpu_sysrt_delete(cpus,RT_WAIT)){ perror("cpu_sysrt_del failed:"); } bitmask_free(cpus); ======================================================================= /* IRQ */ char user_irq_input_buf[45] = "86:2,89:1,87:3,18:4,88:6"; if (cpu_sysrt_irq(user_irq_input_buf, RT_WAIT)){ perror("cpu_sysrt_irq failed"); } ======================================================================= /* Info */ struct bitmask *i_cpus = NULL; if ((i_cpus = bitmask_alloc(cpuset_cpus_nbits())) == NULL) { perror("cpuset: bitmask alloc failed:"); exit (1); } if (cpu_sysrt_info(&i_cpus, QRTCPUS)){ perror("cpu_sysrt_info failed"); 007–4746–014 125 10: Using the REACT Library } .. /* See libbitmask for use of bitmask structure */ .. bitmask_free(i_cpus); ======================================================================= /* Permissions */ gid_t mode_t unsigned long group_id = 117; /* group id or PARAMETER_UNCHANGED, READ_FROM_FILE */ mode = 01644; /* permissions or PARAMETER_UNCHANGED, READ_FROM_FILE*/ mask = 0; mask |= RT_NO_WAIT; /* or RT_WAIT mask |= WRITE_TO_FILE; */ if (cpu_sysrt_perm(group_id, mode, mask) < 0){ perror("Permissions failed"); } 126 007–4746–014 Chapter 11 SGI Linux Trace This chapter discusses the following: • "Overview of SGI Linux Trace" on page 127 • "Installing SGI Linux Trace" on page 128 • "Gathering Trace Data" on page 129 • "Monitoring Trace Events" on page 135 • "Exiting from the tracevisualizer GUI" on page 137 • "Removing SGI Linux Trace" on page 138 Overview of SGI Linux Trace The SGI Linux Trace feature generates traces for kernel events such as interrupt handling, scheduling, and system calls. You can use the SGI Linux Trace tools to record and view trace events and analyze how kernel behavior impacts the execution of applications. SGI Linux Trace consists of the following: • A debug kernel with traces inserted • The tracevisualizer(1) graphical user interface (GUI) • The tracedaemon(1) command, which is available from within the GUI or directly from the command line • Sample platform-specific data files gathered with the frame scheduler enabled and running the simple_pt example program: /var/SLT-DataFiles/x86_64/Default-example.proc /var/SLT-DataFiles/x86_64/slt-cpu.example-all You can view these files using tracevisualizer. 007–4746–014 127 11: SGI Linux Trace For additional details, see the man pages and the tracevisualizer GUI help text in the following file: /usr/share/doc/TraceToolkit-0.9.5-1/Help.tracevisualizer Note: SGI Linux Trace is based on the open-source Linux Trace Toolkit and has been enhanced. Installing SGI Linux Trace To install the sltdebug kernel and SGI Linux Trace, do the following: 1. Log in as the superuser. 2. Install the kernel-sltdebug RPM: [root@linux root]# rpm -Uvh kernel-sltdebug-*.rpm 3. Install the TraceToolkit RPM: [root@linux root]# rpm -Uvh TraceToolkit-*.rpm 4. Do one of the following: a. To use the slt service, set it to start after a reboot and then perform the reboot: [root@linux root]# chkconfig slt on [root@linux root]# reboot b. If you do not want to use the slt service, you must enter the following the commands manually while running the slt kernel. (Without these steps, the tracedaemon will not function.) i. Create the /mnt/debug directory if it does not already exist: [root@linux root]# mkdir /mnt/debug ii. Mount the debugfs filesystem: [root@linux root]# mount -t debugfs debugfs /mnt/debug 128 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide iii. Load the slt module: [root@linux root]# modprobe slt Note: This procedure installs the sltdebug kernel as the default kernel. When you are done with the sltdebug kernel, you should remove the kernel-sltdebug RPM or change the symbolic links in /boot back to the default kernel. If you reboot into a non-sltdebug kernel without removing both the kernel-sltdebug and TraceToolkit RPMs, you must remove the slt module. See "Removing SGI Linux Trace" on page 138. Gathering Trace Data The tracedaemon(1) command reads buffers of trace data provided by the kernel and writes that data to a file. You can run tracedaemon from within the tracevisualizer GUI or from the command line. This section discusses the following: • "Invoking the tracevisualizer GUI" on page 129 • "Recording Events" on page 130 • "Trace Files and Event Types" on page 132 • "Exiting from the tracedaemon Command Line" on page 135 Invoking the tracevisualizer GUI To gather data, you must run the tracevisualizer GUI or the tracedaemon command as root. To allow non-root users to use the command, you can do one of the following: • Configure sudo to allow execution of tracedaemon by specific users. • Configure the command to set setuid root. To invoke the tracevisualizer GUI, enter the following: [user@linux user]# tracevisualizer 007–4746–014 129 11: SGI Linux Trace To write the event data in ASCII format to the specified output file, enter the following: tracevisualizer trace_input_file proc_file output_file For example: [user@linux user]# tracevisualizer slt-cpu.1 Default.proc asciitraceoutput For information about options that filter out the information written to output_file, see the tracevisualizer(1) man page. Recording Events When you want to start recording events, click the stoplight toolbar icon. You can then select options to control the following: • The time duration for which the trace is to be recorded. You can click Start to start recording and Stop to stop recording, or you can enter a specific duration in seconds. The default is 120 seconds. • The CPUs in which threads will be run. Select Bootcpuset: On to run threads in every CPU in the bootcpuset (or CPU 0 if no bootcpuset is present) or select Off to specify specific CPUs in CPUs To Run Threads in one of the following formats: – A list of CPUs: cpu,cpu,... – A range of CPUs (you cannot specify a descending range): cpu-cpu – A mixture of the above: cpu,...cpu-cpu,cpu,... • The sub-buffer size and number. (A sub-buffer is a portion of a CPU buffer. The size of the CPU buffer equals the number of sub-buffers multiplied by the sub-buffer size.) If you experience data being overwritten or dropped, you may need to increase the default values. 130 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide • The size of the data files, which can be one of the following: – Fixed size, sets the size of the sub-buffer and data file. This allows you to continuously collect data within the sub-buffer without filling up all disk space with growing data files. – All data, which collects data into the sub-buffers and writes those sub-buffers out to the ever-growing data file without restrictions on file size. Caution: You do not want to collect events indefinitely, because you would end up with huge trace files that would consume all disk space. ! You can also use the tracedaemon command line to specify the information for recording events: tracedaemon [-h] tracedaemon [-b] [-c] [-n n_subbufs] [-s subbuf_size] [-t seconds] tracedaemon [-n n_subbufs] [-r cpulist] [-s subbuf_size] [-t seconds] 007–4746–014 -b Runs the tracedaemon command and threads on all CPUs listed in the bootcpuset. The default is CPU 0. -c Specifies buffer circular (overwrite) mode, in which data will be written to a fixed size buffer. After the buffer is full, data will be overwritten and lost. -h Displays the usage statement. -n n_subbufs Specifies the number of sub-buffers. The default is 4. -r cpulist Specifies on which CPUs the tracedaemon process and threads can run, where cpulist takes one of the following formats described above. This is useful for keeping traffic off of certain CPUs. By default, per-cpu threads run locally on the CPU in which they are collecting data and the tracedaemon process runs wherever the scheduler puts it. -s subbuf_size Specifies the sub-buffer size in bytes. The default is 524224. 131 11: SGI Linux Trace -t seconds Specifies the total run time in seconds. The default is 120 seconds. For example, to record trace events for 200 seconds and run tracedaemon and threads in the bootcpuset (or CPU 0 if there is no bootcpuset), enter the following: [root@linux root]# tracedaemon -t 200 -b Trace Files and Event Types The event information for each CPU is recorded in a separate file that can be read by tracevisualizer and displayed graphically. The files are located in the same directory from which the tracevisualizer GUI or the tracedaemon command is run. The trace files are named as follows: • slt-cpu.N, with N corresponding to the CPU number. • slt-cpu.all, which combines information from all of the individual slt-cpu.N files. This file is only created when you run tracedaemon from inside the GUI. Note: If you invoked tracedaemon from the command line, the slt-cpu.all file is not created. • Default.proc process/IRQ information file. For example, suppose you have 4 CPUs. If you use the default options in the GUI, the following files would be output: slt-cpu.0 slt-cpu.1 slt-cpu.2 slt-cpu.3 slt-cpu.all Default.proc Table 11-1 summarizes the types of events that are recorded. For more information, see the tracedaemon(8) man page. 132 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Table 11-1 Trace Events that are Recorded Event Type Raw Trace Output Name Event Graph Representation Advanced programmable interrupt controller (APIC) APIC Intr Timer APIC Timer The thread has entered a local APIC timer interrupt. APIC Call Func APIC CF The thread has entered the APIC Interrupt for SMP Call function. The passed function will be run on the CPUs. APIC Intr Exit (no representation) The function execution is finished and the thread is exiting the APIC interrupt processing. FRS Yield FRSYL A frame scheduler application worker thread has called frs_yield() to indicate the end of its processing for the current minor frame. FRS Intr Entry FRSINTENT The frame scheduler interrupt/event processing has started. FRS Intr Exit FRSINTEX The frame scheduler interrupt/event processing has finished. Badbreak BBRK The thread is entering privileged mode to handle a bad system call. Break BRK The thread is entering privileged mode to handle a system call. Fault FAULT The thread is entering privileged mode to handle a system fault. Frame scheduler Interrupt 007–4746–014 Description 133 11: SGI Linux Trace Event Type Scheduler 134 Raw Trace Output Name Event Graph Representation Description Kernel exit (a change will appear in the graph) The interrupt processing is complete and thread is returning to the previous user-mode processing. Interrupt return INTRT The interrupt processing is complete and the thread is returning to the previous kernel-mode processing. IRQ entry IRQ The running thread has been preempted to handle the top-half of an interrupt (IRQ) event. Lightweight LTW The thread is entering privileged mode via a lightweight mechanism such as a fastpath system call. Opfault OPF The thread is entering privileged mode to handle an illegal operation. Pagefault PGF The thread is entering privileged mode to handle a fault in the requested page. Soft IRQ SIRQ:IRQ number Soft-IRQ execution for previous IRQ event. Tasklet action TA:function address Tasklet execution for previous IRQ event. Tasklet hiaction THA:function address High-priority tasklet execution for previous IRQ event. Unaligned UNA The thread is entering privileged mode to handle an unaligned memory access. Sched activate Ac:PID The thread has been moved onto the CPU run queue. The thread is in the ready-to-run state. Sched deactivate De:PID The thread has been moved off the CPU run queue. The thread is in the wait/sleeping state. 007–4746–014 TM REACT Event Type System call Real-Time for Linux® Programmer’s Guide Raw Trace Output Name Event Graph Representation Sched switch Sw:PID The CPU has been allocated to a new thread. The new thread’s register state, stack, and memory mappings are switched onto the CPU. The new thread is in the running state. The previous thread will likely have been deactivated prior to the switch. Syscall entry system call name The thread is entering a system call. System calls can be invoked from user-mode and kernel-mode on Linux. Syscall exit (no representation) The thread has exited a system call handler. Description Exiting from the tracedaemon Command Line If you run tracedaemon from the command line, do one of the following to exit: • Press Ctrl-c • Enter the following, using the process ID (PID) for the tracedaemon process: [root@linux root]# kill -9 tracedaemon_PID Monitoring Trace Events This section discusses the following: • "Opening a Trace File" on page 136 • "Zooming In On An Event" on page 136 • "Changing the Time Frame" on page 136 • "Seeing Process Details" on page 137 • "Seeing All Event Trace Details" on page 137 • "Filtering Events Based on CPU" on page 137 007–4746–014 135 11: SGI Linux Trace For more details, see the GUI help text. Opening a Trace File To monitor events, you must open a trace file and the Default.proc process/IRQ information file. You must have permission to read the files. Use the following menu selection to invoke the Open Trace window: File > Open Trace Note: You could also click on the left-most icon in the icon bar to open a new trace. For more information about the shortcuts in the icon bar, see the GUI help. Enter the path to a trace file and process/IRQ information file, or click the Browse button to open the Select Trace File or > Select Proc File, which lets you select a filename. By default, the trace is shown in the Event Graph output, zoomed out to a great distance. Zooming In On An Event The graph displays the current start time, the end time, the resulting span of time, and the format of the time ruler in either microseconds (us) or nanoseconds (ns). In most cases, the graph will be most useful if you zoom in to a smaller time span. You may also wish to resize the window. To zoom in, select the following from the menu bar or use the + spyglass icon: Tools > Zoom In Changing the Time Frame You can use several methods to change the time frame: • Use the scroll bar at the bottom of the graph for slight changes 136 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide • Left-click the mouse button to zoom in and right-click to zoom out • Use the following menu selection to set the start and end time: Tools > View Time Frame ... • Display the time difference between the two points on the graph by clicking the middle mouse button at the first point (which will display a vertical line drawn as dashes) and at the second point (which will cause a second vertical line to appear), which then displays the time difference in the left of the bottom status bar. Seeing Process Details To see a particular process, click on the Process Analysis tab and select the specific process ID number on the left. The right side of the screen will display characteristics of the process and system call accounting. The Kernel process (process 0) summarizes the system. Seeing All Event Trace Details To see details about all trace entries, click on the Raw Trace tab. Filtering Events Based on CPU To turn events on or off based on CPU both in the Event Graph and Raw Trace output, use the Filter CPU’s menu. Enter the CPUs that you want to display. Exiting from the tracevisualizer GUI To exit from the tracevisualizer GUI, select: File > Exit 007–4746–014 137 11: SGI Linux Trace Removing SGI Linux Trace To remove the sltdebug kernel and SGI Linux Trace, do the following: 1. Log in as the superuser. 2. Remove the kernel-sltdebug RPM: [root@linux root]# rpm -ev kernel-sltdebug-* 3. Remove the TraceToolkit RPM: [root@linux root]# rpm -ev TraceToolkit-* 4. Reboot the system (so that it uses the default kernel). Note: If you remove the kernel-sltdebug RPM but not the TraceToolkit RPM, or if you reboot into a non-sltdebug kernel without removing either RPM, you must do the following to stop the slt service and prevent it from starting after a reboot: [root@linux root]# /etc/init.d/slt stop [root@linux root]# chkconfig slt off 138 007–4746–014 Chapter 12 Using the SGI Linux Trace User Library You can use the SGI Linux Trace (SLT) user library C application programming interface (API) to generate SLT user events, which allow a user program to log data in the same format as the kernel events generated by the SLT debug kernel. No additional SLT kernel events will be generated when logging the user event. This chapter discusses the following: • "SLT User Library Routines" on page 139 • "Accessing SLT User Library Routines" on page 141 • "Example Code Using the SLT User Library Routines" on page 141 • "Generating User and Kernel Data" on page 142 • "Examining the Data" on page 142 • "Manually Including User Events in slt-cpu.all" on page 143 SLT User Library Routines This section discusses the following SLT user library routines: • "slt_close_utrace" on page 139 • "slt_open_utrace" on page 140 • "slt_user_trace" on page 140 slt_close_utrace int slt_close_utrace() The slt_close_utrace routine closes the user channel opened by slt_open_utrace. Return values: none 007–4746–014 139 12: Using the SGI Linux Trace User Library slt_open_utrace int slt_open_utrace() The slt_open_utrace routine opens a user channel that allows user events to be created. You must call this routine before any user events can be created. Return values: none slt_user_trace int slt_user_trace(int EVENT_ID, char* user_string, int cpu) The slt_user_trace routine generates up to five user events with the given information supplied by the user. Input: 140 Value Description int EVENT_ID SLT_USER_N, where N is a numeral in the range 1-5 (such as SLT_USER_1). char* user_string A descriptive string supplied by the user that describes in more detail the type of user event being logged. It can also be used as a search token when examining the user data. The user_string can be up to 16 characters in length. int cpu The CPU on which data was logged (optional). The user can supply the CPU number in order to generate a more accurate representation of the logged data. 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Return values: Value Description 0 Success -1 Error, setting errno Accessing SLT User Library Routines The following inclusion and linkage provides access to SLT user library the from C code: #include #include /* link with -lreact */ Example Code Using the SLT User Library Routines Following is example code using the SLT user library: { int user_tt_fd; if ((user_tt_fd = slt_open_utrace()) < 0) exit(1); slt_user_trace(SLT_USER_1, "My Event String",3 /* cpu */); slt_close_utrace(); } The following example program that is installed with the TraceToolkit illustrates how to use the SLT user: /usr/share/react/SLT/sample-user/u_trace_test.c To compile the example: # cc u_trace_test.c -o u_trace_test -lusertrace -lpthread 007–4746–014 141 12: Using the SGI Linux Trace User Library Generating User and Kernel Data To collect user and kernel data, open the tracevisualizer(1) and collect kernel data in the normal manner. While data collection is in progress, execute the user program with the user events: # ./u_trace_test An slt-cpu.user data file will be created in the same directory from which the user program was executed. This will contain all of the user events for the last execution of u_trace_test. After the data collection has stopped, the tracevisualizer combines all of the data files in its current directory. For example, suppose you had the following files: slt-cpu.0 slt-cpu.1 ... slt-cpu.N ll of the above files will be combined into one file, slt-cpu.all. Note: To include the user events in slt-cpu.all, the slt-cpu.user file must be in the same directory as the slt-cpu.X files. If this was not the case, see "Manually Including User Events in slt-cpu.all" on page 143. Examining the Data The slt-dump utility program that is installed with the SGI Linux Trace Toolkit will assist in examining the SLT user and kernel data created. To compile it, do the following: # /usr/share/react/SLT/tests/slt-dump.c # cc slt-dump.c -o slt-dump Due to the amount of data collected, you should redirect the output to a .txt file so that you can examine it with an editor of your choice. For example: # ./slt-dump -cf slt-cpu.all > slt-data-9-20-13:21.txt 142 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Manually Including User Events in slt-cpu.all To include the user events in slt-cpu.all, the slt-cpu.user file must be in the same directory as the slt-cpu.X files. If slt-cpu.all was created without slt-cpu.user in the directory, do the following to manually include the events: 1. Delete the slt-cpu.all file. 2. Copy slt-cpu.user to the same directory as the slt-cpu.X files. 3. Restart the tracevisualizer. This will trigger the routine to merge all the data files. 007–4746–014 143 Chapter 13 Troubleshooting This chapter discusses the following: • "Diagnostic Tools" on page 145 • "Problem Removing /rtcpus" on page 148 Diagnostic Tools You can use the following diagnostic tools: • Use the cat(1) command to view the /proc/interrupts file in order to determine where your interrupts are going: [user@linux user]% cat /proc/interrupts For an example, see Appendix A, "Example Application" on page 149. • Use the profile.pl(1) Perl script to do procedure-level profiling of a program and discover latencies. For more information, see the profile.pl(1) man page. • Use the following ps(1) command to see where your threads are running: [user@linux user]% ps -FC processname For an example, see Appendix A, "Example Application" on page 149. To see the scheduling policy, real-time priority, and current processor of all threads on the system, use the following command: [user@linux user]% ps -eLo pid,tid,class,rtprio,psr,cmd For more information, see the ps(1) man page. • Use the top(1) command to display the largest processes on the system. For more information, see the top(1) man page. • Use the strace(1) command to determine where an application is spending most of its time and where there may be large latencies. The strace command is a very flexible tool for tracing application activities and can be used for tracking down latencies in an application. Following are several simple examples: 007–4746–014 145 13: Troubleshooting – To see the amount of time being used by system calls in the form of histogram data for a program named hello_world, use the following: [root@linux root]# strace -c hello_world execve("./hello_world", ["hello_world"], [/* 80 vars */]) = 0 Hello World % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------27.69 0.000139 28 5 3 open 20.92 0.000105 15 7 mmap 10.76 0.000054 54 1 write 7.57 0.000038 13 3 fstat 6.57 0.000033 17 2 1 stat 5.98 0.000030 15 2 munmap 4.58 0.000023 12 2 close 4.38 0.000022 22 1 mprotect 4.18 0.000021 21 1 madvise 2.99 0.000015 15 1 read 2.39 0.000012 12 1 brk 1.99 0.000010 10 1 uname ------ ----------- ----------- --------- --------- ---------------100.00 0.000502 27 4 total – You can record the actual chronological progression through a program with the following command (line breaks added for readability): [root@linux root]# strace -ttT hello_world 14:21:03.974181 execve("./hello_world", ["hello_world"], [/* 80 vars */]) = 0 .. 14:21:03.976992 mmap(NULL, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2000000000040000 <0.000007> 14:21:03.977053 write(1, "Hello World\n", 12Hello World ) = 12 <0.000008> 14:21:03.977109 munmap(0x2000000000040000, 65536) = 0 <0.000009> 14:21:03.977158 exit_group(0) = ? The time stamps are displayed in the following format: hour:minute:second.microsecond The execution time of each system call is displayed in the following format: 146 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide Note: You can use the -p option to attach to another already running process. For more information, see the strace(1) man page. • Use the tracevisualizer command. See Chapter 11, "SGI Linux Trace" on page 127. • To find the CPU-to-core numbering scheme, examine the following fields in the /proc/cpuinfo file: processor physical id core id For example, the following output for a third-party x86-64 system shows that logical CPU 0 (processor 0) and CPU 2 (processor 2) are cores sharing the same socket: (physical id 0) 007–4746–014 processor ... physical id siblings core id cpu cores : 0 processor ... physical id siblings core id cpu cores : 2 : : : : : : : : 0 2 0 2 0 2 1 2 147 13: Troubleshooting The following output for an Altix UV 1000 or Altix UV 100 system shows two logical processors CPU 0 (processor 0) and CPU 8 (processor 8): processor .. physical id siblings core id cpu cores : 0 processor .. physical id siblings core id cpu cores : 8 : : : : : : : : 0 16 0 8 1 16 0 8 Note the following: – CPU 0 is housed in the first socket on the system (physical id 0). This socket has 8 CPU cores. Each of those cores will have two logical CPUs if hyperthreading is enabled. – CPU 8 is housed in the second socket (physical id 1). This socket has 8 CPU cores. Each of those cores will have two logical CPUs if hyperthreading is enabled. Each logical CPU is in the first core on its respective socket (core ID 0). Problem Removing /rtcpus You should stop real-time processes before using the --disable option. However, the script will attempt to remove the process from the real-time CPUs and display the following failure message if it was unable to move them: "*** Problem removing /rtcpus/rtcpu3. cpuset*** Try again. If that doesn’t work check /dev/cpuset/rtcpus/rtcpu3/tasks for potential problem PIDS; 148 007–4746–014 Appendix A Example Application This appendix discusses an example of a multithreaded application that demonstrates using external interrupts and other aspects of REACT. It uses netlink sockets to communicate from kernel space to user space. You can use it as a performance benchmark to compare between machines or settings within REACT, such as for external interrupts, cpusets, and CPU isolation. The application is composed of the following examples: • A kernel module, which shows examples of the following concepts: – Creating and building a driver with a standard miscellaneous device interface – Setting up and registering a external interrupt handler – Creating and binding a kernel thread – Using netlink sockets to communicate with a user application • A user-space application, which shows examples of the following concepts : – Assigning threads to cpusets, thereby changing thread/CPU affinity – Changing thread/CPU affinity without cpusets – Creating, destroying, and signaling threads – Changing a thread’s scheduling policies and priorities – Locking memory – Setting up a netlink socket to communicate with a kernel thread This example puts the data into a matrix and multiplies two matrices together. The worker thread displays the multiplication and calculates how long it takes to multiply the two matrices together. You can modify the size of the matrix to see how it effects the time to calculate the multiplication. For example, you could use a field-programmable gate array (FPGA) to implement the multiply function in order to show how much faster it is under these circumstances than under normal calculation. You could also run on two different platforms to compare the speed of integer multiplication. 007–4746–014 149 A: Example Application This program runs as a multithreaded process. The main process launches the following threads, sets each thread’s scheduling policy and priority, and displays the thread policy and priority information: • The receiving thread (netlink_receive) does the following: 1. Tells the kernel to start the processing of interrupts (a one-time event). 2. Locks its current and future memory (if requested). 3. Uses the example kernel module driver to do the following: a. Waits for messages from the kernel netlink socket. b. Signals the worker thread with the data from the driver. • The worker thread (worker_routine) does the following: 1. Waits to be signaled by the receive thread for data. 2. Fills two matrices with the data and multiplies them together. The output will be printed to the console. 3. Calculates the time it takes for the matrices to by multiplied together. • The interrupt handler (extint_run) runs when a hardware external interrupt is received. It wakes up the bench_extintd thread. • The kernel thread (bench_extintd) gets data, sends messages with the data to the receiving thread (netlink_receive), and then sleeps until another interrupt occurs. netlink_receive is set at a higher priority than the time-consuming worker_routine. Figure A-1 describes the example. Step 1 occurs once, but steps 2 through 4 are repeated for each external interrupt. 150 007–4746–014 TM REACT Interrupt Context Kernal Space Real-Time for Linux® Programmer’s Guide User Space netlink_receive Start processing interrupts and sending messages, and create communication link 1 External interrupt extint_run Wake up bench_extint bench_extintd 2 Get data Send messages with data Sleep netlink_receive 3 Receive data Signal worker_routine worker_routine 4 Put data into matrix Do matrix work Figure A-1 Example Work Flow The rest of this section discusses the following: • "Setting Up External Interrupts" on page 151 • "Building and Loading the Kernel Module" on page 152 • "Building the User-Space Application" on page 153 • "Running the Sample Application" on page 153 • "set_affinity code" on page 156 Setting Up External Interrupts To set up external interrupts, do the following: 1. Log in to the target system as root. 2. Load the ioc4_extint module: [root@linux root]# modprobe ioc4_extint 007–4746–014 151 A: Example Application 3. Insert the required information into the source, mode, and period files in the /sys/class/extint/extint0/ directory. For example: [root@linux root]# echo loopback >/sys/class/extint/extint0/source [root@linux root]# echo toggle >/sys/class/extint/extint0/mode [root@linux root]# echo 1000000 >/sys/class/extint/extint0/period For more information about external interrupts see Chapter 3, "External Interrupts" on page 17. Building and Loading the Kernel Module To build the bench_extint_mod application kernel module, do the following on the target system: 1. Log in to the target system as root. 2. Ensure that the kernel-source-*.rpm RPM is installed. 3. Ensure that the sgi-extint-kmp-modvers RPM is installed. 4. Copy the Module.symvers file from its location in the directory defined by the uname -r output to the kernel directory: [root@linux root]# cp /usr/share/extint/‘uname -r‘/Module.symvers /usr/share/react/examples/bench/kernel/. 5. Change to the kernel directory: [root@linux root]# cd /usr/share/react/samples/bench/kernel 6. Build the bench_extint_mod.ko file: [root@linux kernel]# make -C /lib/modules/‘uname -r‘/build SUBDIRS=$PWD modules For more information, see the uname(1) man page. 7. Copy the bench_extint_mod.ko file to the directory defined by the uname -r output: [root@linux kernel]# cp bench_extint_mod.ko /lib/modules/‘uname -r‘ 8. Make a dependency file: [root@linux kernel]# depmod 152 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide For more information, see the depmod(8) man page. 9. Load the bench_extint_mod module: [root@linux kernel]# modprobe bench_extint_mod For more information, see the modprobe(8) man page. 10. Use the bench_extint_mod kernel module with the bench_example application. Note: You must load the ioc4_extint module before the bench_extint_mod module. Building the User-Space Application To build the user-space module, do the following: 1. Change to the user directory: [root@linux root]# cd /usr/share/react/samples/bench/user 2. Build the module: [root@linux root]$ make Running the Sample Application You can run the bench_example application in the following modes: • Matrix multiply mode receives data from the kernel module and puts that data into a matrix. After two matrices are full, it multiplies them together and calculates the amount of time taken for the calculation. See "Matrix Multiply Mode Examples" on page 155. • Netlink socket bench mode causes the application to send multiple messages from kernel space to user space during one iteration. The number of messages sent per iteration depends upon notification from the user application to start sending messages. See "Netlink Socket Benchmark Mode Examples" on page 155. 007–4746–014 153 A: Example Application Do the following: • Ensure that you have the bench_extint_mod module loaded by using the lsmod(1) command, which should show it in the module list. For example: [root@linux root]# lsmod Module bench_extint_mod ioc4_extint ioc4 extint Size 546232 27272 24704 32008 Used by 0 0 1 ioc4_extint 2 bench_extint_mod,ioc4_extint If the output does not include bench_extint_mod, follow the instructions in "Building and Loading the Kernel Module" on page 152. • Execute the bench command as desired. The bench command has the following options: 154 -b messages Runs the application in benchmark mode with the specified number of messages in each send. messages is an integer in the range 1 through 100. (If you enter an invalid number, the default is 100.) -h Prints usage instructions. -k cpu Specifies the CPU where the kthread will run. -m Locks memory. -p cpu Specifies the CPU where the bench process will run. -r cpu Specifies the CPU where the receive thread will run. -s size Specifies the size of buffers in bytes for network socket bench mode. The default is 1024. You can vary the size of the buffers to see the impact on performance. -t sec Specifies the total run time in seconds, with a maximum of 30 seconds. The default is 30. 007–4746–014 TM REACT -w cpu Real-Time for Linux® Programmer’s Guide Specifies the CPU where the worker thread will run. Matrix Multiply Mode Examples To run in matrix multiply mode for 30 seconds: [root@linux root]# ./bench -t30 To run with memory locked and bench processes running on CPU 2 (real-time or non-real-time): [root@linux root]# ./bench -m -p2 -t30 To run the bench process on CPU 3 and the worker and receive threads on CPU 2: [root@linux root]# ./bench -m -p3 -r2 -w2 -t30 See also "set_affinity code" on page 156. Netlink Socket Benchmark Mode Examples The following shows an example in bench mode that runs for 30 seconds with memory locked and a buffer size of 512 bytes. There are 50 messages in each send. The process is running on CPU 1, the receive thread running on CPU 2, the worker thread is running on CPU 3, and the kernel thread is running on CPU 1: [root@linux root]# ./bench -m -t30 -p1 -r2 -w3 -k1 -b50 -s512 If you have multiple terminals open, you can run the following tail(1) and ps(1) commands to see where things are running: [root@linux root]# tail -f /var/log/messages Feb 16 08:54:05 dewberry kernel: bench_extint init Feb 16 08:54:40 dewberry kernel: bench_extint ran 14958, thread ran 14958 dropped msgs 0 Feb 16 08:54:40 dewberry kernel: ioctl unregister bench_extint [root@linux root]# ps -eLF UID PID PPID LWP C NLWP SZ RSS PSR STIME TTY TIME CMD root 10076 6747 10076 0 3 5951 18696 1 11:34 pts/0 00:00:00 ./bench -m -t30 -p1 -r2 -w3 -k1 -b50 -s512 root 10076 6747 10078 11 3 5951 18696 2 11:34 pts/0 00:00:00 ./bench -m -t30 -p1 -r2 -w3 -k1 -b50 -s512 root root 10076 10077 6747 10079 99 15 10077 10 3 1 5951 18696 0 0 3 11:34 pts/0 1 11:34 ? 00:00:04 ./bench -m -t30 -p1 -r2 -w3 -k1 -b50 -s512 00:00:00 [bench_exintd] 007–4746–014 155 A: Example Application set_affinity code You can use the following functions to set process and thread affinity for real-time and non real-time CPUs. You can compile this file as part of another application, but you must link it against the libcpuset. #include #include #include "errors.h" #define CPUSET_ROOT "/dev/cpuset" #define BITS_PER_LONG (sizeof(unsigned long) * 8) pid_t _gettid(){ return syscall(__NR_gettid); } void do_pthread_affinity(int cpu) { int nrcpus = cpuset_cpus_nbits(); int bitmask_size = (nrcpus/BITS_PER_LONG); unsigned long cpus[bitmask_size]; pid_t tid = _gettid(); cpus[cpu/64] = 1 << (cpu % 64); if (sched_setaffinity(tid, sizeof(cpus), cpus)) { perror("set_affinity"); exit(1); } } void set_thread_affinity(int cpu) { char path[50],fullpath[50]; sprintf(path, "/rtcpus/rtcpu%d", cpu); sprintf (fullpath, CPUSET_ROOT "/rtcpus/rtcpu%d",cpu); if (access(fullpath, F_OK) != 0) { /* no cpuset, so try moving it without */ 156 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide do_pthread_affinity(cpu); return; } /* Move the process into the cpuset */ if (cpuset_move(_gettid(), path) == -1) { perror("cpuset_move"); exit(1); } } /* Set the current proc to run on cpu . */ void set_process_affinity(int cpu) { int nrcpus = cpuset_cpus_nbits(); int bitmask_size = (nrcpus/BITS_PER_LONG); unsigned long cpus[bitmask_size]; char path[50],fullpath[50]; unsigned long mask; cpus[cpu/64] = 1 << (cpu % 64); sprintf(path, "/rtcpus/rtcpu%d", cpu); sprintf (fullpath, CPUSET_ROOT "/rtcpus/rtcpu%d",cpu); if (access(fullpath, F_OK) != 0) { /* no cpuset, so try moving it without */ if (sched_setaffinity(getpid(), sizeof(cpus), cpus)) { perror("set_process_affinity"); } return; } /* Move the process into the cpuset */ if (cpuset_move(getpid(), path) == -1) perror("cpuset_move"); } 007–4746–014 157 Appendix B High-Resolution Timer Example Example B-1 demonstrates the use of SGI high-resolution timers. It will run high-resolution POSIX timers in both relative mode and absolute mode. Example B-1 High-Resolution Timer /***************************************************************************** * * * This sample program demonstrates the use of SGI high resolution timers * * in SGI REACT. * * * * A simple way to build this sample program is: * * cc -o timer_sample timer_sample.c -lrt * * * * Invocation example (500 usec timer): * * ./timer_sample 500 * * * * Invocation example (500 usec timer on realtime cpu 2): * * cpuset --invoke=/rtcpu2 --invokecmd=./timer_sample 500 * * * *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include struct timespec time1; int flag; /* Timer has triggered, get current time and indicate completion */ 007–4746–014 159 B: High-Resolution Timer Example void sigalarm(int signo) { clock_gettime(CLOCK_REALTIME,&time1); flag = 1; } int timer_test(int clock_id, long nanosec) { struct itimerspec ts; struct sigevent se; struct sigaction act; sigset_t sigmask; struct timespec sleeptime, time0; timer_t timer_id; long i; int signum = SIGRTMAX; int status; /* Set up sleep time for loops: */ sleeptime.tv_sec = 1; sleeptime.tv_nsec = 0; /* Set up signal handler: */ sigfillset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = sigalarm; sigaction(signum, &act, NULL); /* Set up timer: */ memset(&se, 0, sizeof(se)); se.sigev_notify = SIGEV_SIGNAL; se.sigev_signo = signum; se.sigev_value.sival_int = 0; status = timer_create(clock_id, &se, &timer_id); if (status < 0) { perror("timer_create"); return -1; } /* Start relative timer: */ 160 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide ts.it_value.tv_sec = nanosec / 1000000000; ts.it_value.tv_nsec = (nanosec % 1000000000); ts.it_interval.tv_sec = 0; ts.it_interval.tv_nsec = 0; printf("Waiting for timeout of relative timer: "); fflush(stdout); flag = 0; /* Get current time for reference */ clock_gettime(CLOCK_REALTIME,&time0); /* * There will be some latency between getting the start time above, * and setting the relative time in timer_settime. */ status = timer_settime(timer_id, 0, &ts, NULL); if (status < 0) { perror("timer_settime"); return -1; } /* Loop waiting for timer to go off */ while (!flag) nanosleep(&sleeptime, NULL); if (time1.tv_nsec < time0.tv_nsec) printf("Total time=%luns\n", 1000000000LL - (time0.tv_nsec - time1.tv_nsec) + ((time1.tv_sec - time0.tv_sec -1)*1000000000LL)); else printf("Total time=%luns\n", time1.tv_nsec - time0.tv_nsec + ((time1.tv_sec - time0.tv_sec)*1000000000LL)); /* Start absolute timer: */ printf("Waiting for timeout of absolute timer: "); fflush(stdout); flag = 0; /* Get current time and add timeout to that for absolute time */ clock_gettime(CLOCK_REALTIME,&time0); i = time0.tv_nsec + (nanosec % 1000000000); ts.it_value.tv_nsec = i % 1000000000; ts.it_value.tv_sec = (time0.tv_sec + (nanosec / 1000000000)) + 007–4746–014 161 B: High-Resolution Timer Example (i / 1000000000); /* There should be less latency than what we saw above */ status = timer_settime(timer_id, TIMER_ABSTIME, &ts, NULL); if (status < 0) { perror("timer_settime"); return -1; } /* Loop waiting for timer to go off */ while (!flag) nanosleep(&sleeptime, NULL); if (time1.tv_nsec < time0.tv_nsec) printf("Total time=%luns\n", 1000000000LL - (time0.tv_nsec - time1.tv_nsec) + ((time1.tv_sec - time0.tv_sec -1)*1000000000LL)); else printf("Total time=%luns\n", time1.tv_nsec - time0.tv_nsec + ((time1.tv_sec - time0.tv_sec)*1000000000LL)); /* Cleanup */ timer_delete(timer_id); return 0; } int main(int argc, char *argv[]) { long timeout; if (argc < 2) { printf("usage: %s \n", basename(argv[0])); return -1; } timeout = atol(argv[1]); if (timeout <= 0) { printf("Timeout negative or 0 specified\n"); printf("usage: %s \n", basename(argv[0])); return -1; } 162 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide /* Run timer_test with high resolution timer. */ printf("\nRunning with CLOCK_REALTIME (normal resolution)..\n"); if (timer_test(CLOCK_REALTIME, timeout * 1000)) { return -1; } } 007–4746–014 163 Appendix C Sample User-Level Interrupt Programs The following applications demonstrate some of the user-level interrupt (ULI) interface: • "uli_sample Sample Program" on page 165 • "uli_ei Sample Program" on page 166 The applications are installed with the ULI RPM and are located in: /usr/share/react/uli/examples/ uli_sample Sample Program The uli_sample program registers for notification on CPU 0 for occurrences of a specified interrupt number. To use uli_sample, do the following: 1. Load the ULI feature kernel module: [root@linux root]# modprobe uli 2. Change to the directory containing uli_sample: [root@linux root]# cd /usr/share/react/uli/examples/ 3. Run uli_sample, where interrupt# is the interrupt number: [root@linux root]# ./uli_sample interrupt# For example, to register for notification on CPU 0 for occurrences of the interrupt number 34, enter the following: [root@linux root]# ./uli_sample 34 007–4746–014 165 C: Sample User-Level Interrupt Programs uli_ei Sample Program The uli_ei program requires the external interrupt to run and prints a message every time the external interrupt line is toggled. To use uli_ei, do the following: 1. Load the ULI feature kernel module, if not already done: [root@linux root]# modprobe uli 2. Load the external interrupt kernel module: [root@linux root]# modprobe ioc4_extint 3. Set the external interrupt mode to toggle: [root@linux root]# echo toggle > /sys/class/extint/extint0/mode 4. Change to the directory containing uli_ei: [root@linux root]# cd /usr/share/react/uli/examples/ 5. Run uli_ei: [root@linux root]# 166 ./uli_ei 007–4746–014 Glossary activity When using the frame scheduler, the basic design unit: a piece of work that can be done by one thread or process without interruption. You partition the real-time program into activities and use the frame scheduler to invoke them in sequence within each frame interval. address space The set of memory addresses that a process may legally access. The potential address space in Linux is 264; however, only addresses that have been mapped by the kernel are legally accessible. APIC Advanced programmable interrupt controller. arena A segment of memory used as a pool for allocation of objects of a particular type. asynchronous I/O I/O performed in a separate process so that the process requesting the I/O is not blocked waiting for the I/O to complete. average data rate The rate at which data arrives at a data collection system, averaged over a given period of time (seconds or minutes, depending on the application). The system must be able to write data at the average rate, and it must have enough memory to buffer bursts at the peak data rate. BAR Base address register. clock tick A measure of time determined by the resolution of the real-time clock. 007–4746–014 167 Glossary control law processor A type of stimulator provides the effects of laws of physics to a machine. controller thread A top-level process that handles startup and termination. CPU Central Processing Unit refers to cores (not sockets). device driver Code that operates a specific hardware device and handles interrupts from that device. device service time The time the device driver spends processing the interrupt and dispatching a user thread. device special file The symbolic name of a device that appears as a filename in the /dev directory hierarchy. The file entry contains the device numbers that associate the name with a device driver. external interrupt A hardware signal from an I/O device, such as the SGI IOC4 chip, that is generated in response to a voltage change on an externally accessible hardware port. fastcall A version of a function call that has been optimized in assembler in order to bypass the context switch typically necessary for a full system call. file descriptor A number returned by open() and other system functions to represent the state of an open file. The number is used with system calls such as read() to access the opened file or device. 168 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide firm real-time program A program that experiences a significant error if it misses a deadline but can recover from the error and can continue to execute. See also hard real-time program and soft real-time program. frame interval The amount of time that a program has to prepare the next display frame. A frame rate of 60 Hz equals a frame interval of 16.67 milliseconds. frame rate The frequency with which a simulator updates its display, in cycles per second (Hz). Typical frame rates range from 15 to 60 Hz. frame scheduler A process execution manager that schedules activities on one or more CPUs in a predefined, cyclic order. frame scheduler controller The thread or process that creates a frame scheduler. Its thread or process ID is used to identify the frame scheduler internally, so a thread or process can only be identified with one scheduler. frame scheduler controller thread The thread that creates a frame scheduler. guaranteed rate A rate of data transfer, in bytes per second, that definitely is available through a particular file descriptor. hard real-time program A program that experiences a catastrophic error if it misses a deadline. See also firm real-time program and soft real-time program. hardware latency The time required to make a CPU respond to an interrupt signal. 007–4746–014 169 Glossary hardware-in-the-loop (HWIL) simulator A simulator in which the role of operator is played by another computer. interrupt A hardware signal from an I/O device that causes the computer to divert execution to a device driver. interrupt information template An array of frs_intr_info_t data structures, where each element in the array represents a minor frame. interrupt propagation delay See hardware latency. interrupt redirection The process of directing certain interrupts to specific real-time processors and directing other interrupts away from specific real-time processors in order to minimize the latency of those interrupts. interrupt response time The total time from the arrival of an interrupt until the user process is executing again. Its main components are hardware latency, software latency, device service time, and mode switch. interrupt service routine (ISR) A routine that is called each time an interrupt occurs to handle the event. interval time counter (ITC) A 64–bit counter that is scaled from the CPU frequency and is intended to allow an accounting for CPU cycles. interval timer match (ITM) register A register that allows the generation of an interval timer when a certain ITC value has been reached. 170 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide IPI Interprocessor interrupt. IRQ Interrupt request. isolate To remove the Linux CPU from load balancing considerations, a time-consuming scheduler operation. jitter Numerous short interruptions in process execution. locks Memory objects that represent the exclusive right to use a shared resource. A process that wants to use the resource requests the lock that (by agreement) stands for that resource. The process releases the lock when it is finished using the resource. See semaphore. LSM Linux security model. major frame The basic frame rate of a program running under the frame scheduler. master scheduler The first frame scheduler, which provides the time base for the others. See also slaves and sync group. microsecond (us or usec) 1 microsecond is .000001 seconds. Abbreviated as us or usec. millisecond (ms or msec) 1 millisecond is .001 seconds. Abbreviated as ms or msec. 007–4746–014 171 Glossary minor frame The scheduling unit of the frame scheduler, the period of time in which any scheduled thread or process must do its work. mode switch The time it takes for a thread to switch from kernel mode to user mode. MPI Message passing interface. nanosecond (ns) 1 nanosecond is .000000001 seconds. Abbreviated as ns or nsec. new pthreads library (NPTL) The Linux pthreads library shipped with 2.6 Linux. overrun When incoming data arrives faster than a data collection system can accept it and therefore data is lost. overrun exception When a thread or process scheduled by the frame scheduler should have yielded before the end of the minor frame but did not. page fault The hardware event that results when a process attempts to access a page of virtual memory that is not present in physical memory. pages The units of real memory managed by the kernel. Memory is always allocated in page units on page-boundary addresses. Virtual memory is read and written from the swap device in page units. 172 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide peak data rate The instantaneous maximum rate of input to a data collection system. The system must be able to accept data at this rate to avoid overrun. See also average data rate. process The entity that executes instructions in a Linux system. A process has access to an address space containing its instructions and data. pthread A thread defined by the POSIX standard. Pthreads within a process use the same global address space. Also see thread. rate-monotonic analysis A technique for analyzing a program based on the periodicities and deadlines of its threads and events. rate-monotonic scheduling A technique for choosing scheduling priorities for programs and threads based on the results of rate-monotonic analysis. restrict To prevent a CPU from running scheduled processes. scheduling discipline The rules under which an activity thread or process is dispatched by a frame scheduler, including whether or not the thread or process is allowed to cause overrun or underrun exceptions. segment Any contiguous range of memory addresses. Segments as allocated by Linux always start on a page boundary and contain an integral number of pages. semaphore A memory object that represents the availability of a shared resource. A process that needs the resource executes a p operation on the semaphore to reserve the resource, 007–4746–014 173 Glossary blocking if necessary until the resource is free. The resource is released by a v operation on the semaphore. See also locks. shield To switch off the timer (scheduler) interrupts that would normally be scheduled on a CPU. simulator An application that maintains an internal model of the world. It receives control inputs, updates the model to reflect them, and outputs the changed model as visual output. slaves The other schedulers that take their time base interrupts from the master scheduler. See also sync group. soft real-time program A program that can occasionally miss a deadline with only minor adverse effects. See also firm real-time program and hard real-time program. software latency The time required to dispatch an interrupt thread. spraying interrupts The distribution of I/O interrupts across all available processors as a means of balancing the load. stimulator An application that maintains an internal model of the world. It receives control inputs, updates the model to reflect them, and outputs the changed model as nonvisual output. sub-buffer A portion of a CPU buffer. The size of the CPU buffer equals the number of sub-buffers multiplied by the sub-buffer size. 174 007–4746–014 TM REACT Real-Time for Linux® Programmer’s Guide sync group The combination of a master scheduler and slaves. thread An independent flow of execution that consists of a set of registers (including a program counter and a stack). Also see pthread. TLB Translation lookaside buffer, which translates CPU virtual memory addresses to bus physical memory addresses. transport delay The time it takes for a simulator to reflect a control input in its output display. Too long a transport delay makes the simulation inaccurate or unpleasant to use. ULI User-level interrupt ULI process A user process that has registered a function with the kernel, linked into the process in the normal fashion, to be called when a particular interrupt is received. underrun exception When a thread or process scheduled by the frame scheduler should have started in a given minor frame but did not (owing to being blocked), an underrun exception is signaled. See overrun exception. unsynchronized drifty ITCs Systems with processors that run at the same speed but do not have the same clock source and therefore their ITC values may experience drift relative to one another. us (or usec) Microsecond (1 us is .000001 seconds). 007–4746–014 175 Glossary user-level interrupt (ULI) A facility that allows a hardware interrupt to be handled by a user process. 176 007–4746–014 Index A abstraction layer, 17 access to select REACT features, 116 activity thread management, 68 address space (locking in memory), 102 advanced programmable interrupt controller (APIC), 133 aircraft simulator, 3 API REACT library, 117 SLT user library, 139 application example, 149 asynchronous I/O, 91 average data rate, 5 B /boot, 107 /boot cpuset, 117, 120 BOOTCPUS, 120 bootcpuset, 42, 107 BOOTMEMS, 120 C C language, 7 cache warming, 63 callout deregistration, 30 callout mechanism, 29 callout registration, 29 CAP_DAC_OVERRIDE authority, 116 cat, 145 clock processor, 43 clock_gettime, 13, 14 007–4746–014 CLOCK_MONOTONIC, 13 CLOCK_REALTIME, 13 clock_settime, 13 clocks, 12 close a user trace routine, 139 configuration, 107 console interrupts, 11 control law process stimulator, 4 controller thread, 66, 77 core ID, 148 cores requirement, 7 CPU restricting, 10, 45 workload control, 39 CPU 0, 43 CPU affinity routine, 121 CPU designation routine, 124 CPU-bound, 9 CPU-to-core numbering scheme, 147 cpu_shield, 118 cpu_sysrt_add, 119 cpu_sysrt_delete, 120 cpu_sysrt_info, 120 cpu_sysrt_irq, 121 cpu_sysrt_perm, 122 cpu_sysrt_runon, 124 CPUs in the /boot cpuset, 120 cpuset, 42, 115 cpuset-utils, 7 cpusets, 54 create real-time routine, 119 cycles per second, 3 D data collection system, 5 177 Index debug kernel, 6 delete real-time routine, 120 deregistration of callout, 30 dev attribute file, 18 /dev/extint#, 102 device service time, 48, 51 device special file, 102 device-driver time base, 55 diagnostic tools, 145 direct RTC access, 14 disciplines, 9 disk I/O optimization, 91 distributed applications, 15 dplace, 116 driver creation and building, 149 driver deregistration, 28 driver interface, 23 driver registration, 24 driver template, 31 E earnings-based scheduler, 10 event recording, 131 events recorded by tracedaemon, 132 examples API code REACT library , 124 SLT user library, 141 matrix multiply mode, 155 multithreaded application, 149 Netlink socket benchmark mode, 155 exception types, 81 external interrupt ingest, 36 external interrupt setup and registration, 149 external interrupt with frame scheduler, 70 external interrupts, 17 extint, 7, 19, 102 extint_device, 23 extint_properties, 23 178 F fastcall, 13 features, 6 feedback loop, 2 filter tracedaemon events based on CPU, 137 firm real-time program, 1 first-in-first-out, 10 flock system call, 20 fork(), 78 FPGA, 149 frame interval, 3 frame rate, 2 frame scheduler, 6, 53 advantages, 12 API, 58 background discipline, 73 basics, 54 concepts, 53 continuable discipline, 73 controller thread, 66 current frame extension, 82 design process, 75 exception counts, 84 exception handling, 81 exception policies, 83 exception types, 81 external interrupt, 70 frame scheduler controller, 58 frs_run flag, 64 frs_yield flag, 64 high-resolution timer, 70 interval timers not used with, 89 library interface for C programs, 60 major frame, 56 managing activity threads, 68 minor frame, 56 multiple exceptions, 83 multiple synchronized, 66 overrun exception, 71, 81 overrunnable discipline, 72 007–4746–014 TM REACT overview, 11 pausing, 67 preparing the system, 76 process outline for single, 77 real-time discipline, 71 repeat frame, 82 scheduling disciplines, 71 scheduling rules of, 64 sequence error handling, 88 signal use under, 86 signals in an activity thread, 87 signals produced by, 86, 87 starting up a single scheduler, 66 starting up multiple schedulers, 67 synchronized schedulers, 78 thread programming model, 55 thread structure, 62 time base selection, 55, 69 underrun exception, 71, 81 underrunable discipline, 72 using consecutive minor frames, 73 warming up cache, 63 frame scheduler controller, 58 receives signals, 87 frs See "frame scheduler", 53 frs_create(), 60, 77 frs_create_master(), 60, 78, 79 frs_create_slave(), 60, 80 frs_create_vmaster(), 60, 78, 79 frs_destroy(), 62, 78, 80, 81 frs_enqueue(), 60, 67, 78 frs_fsched_info_t, 58 frs_getattr(), 62, 84 frs_getqueuelen(), 61, 68 frs_intr_info_t, 59 frs_join, 61 frs_join(), , 62, 67, 78, 80 frs_overrun_info_t(), 84 frs_pinsert(), 61, 68 frs_premove(), 62, 68, 87 frs_pthread_enqueue(), 61, 64, 71, 78, 80 007–4746–014 Real-Time for Linux® Programmer’s Guide frs_pthread_getattr(), 62, 84 frs_pthread_insert, 61 frs_pthread_insert(), 68 frs_pthread_readqueue(), 61, 68 frs_pthread_register(), 62 frs_pthread_remove(), 62, 68, 87 frs_pthread_setattr(), 61, 83 example code, 84 frs_queue_info_t, 58 frs_readqueue(), 61, 68 frs_recv_info_t, 59 frs_resume(), 61, 67 frs_run, 64 frs_setattr(), 61, 83 frs_start, 61 frs_start(), 67, 78, 80 frs_stop, 61 frs_stop(), 67 frs_t, 58 frs_userintr(), 61 frs_yield, , 61, 62, 64, 73 fsync, 92 G generate user events routine, 140 generating a REACT system configuration, 107 global variables and ULI, 101 _GNU_SOURCE, 20 ground vehicle simulator, 3 H hard real-time program, 1 hardware latency, 48, 49 hardware–in–the–loop simulator, 4 high-output modes, 34 high-priority tasklet execution event, 134 high-resolution timer, 70, 159 179 Index HUB hardware timers, 53 hyperthreading, 148 Hz (hertz, cycles per second), 3 I I/O interrupts, 11 I/O-bound, 9 IDE driver, 33 illegal operation event, 134 implementation functions, 24 include files, 124, 141 ingest section for external interrupts, 36 interchassis communication, 14 internal driver circuit I/O connectors, 37 interrupt group. See interrupt group, 69 See also user-level interrupt (ULI), 97 interrupt control, 11 interrupt events, 134 interrupt group, 69 interrupt information template, 59 interrupt notification interface, 28 interrupt propagation delay, 49 interrupt redirection, 43 interrupt response time components, 48 definition of, 47 minimizing, 51 interrupt return event, 134 interrupt service routines (ISRs), 51, 97 interval See "frame interval", 3 interval timer, 89 introduction, 1 IOC4 chip, 17 IOC4 driver, 32 ioc4_extint, 102 IOC4–specific character special device and class, 31 IRQ redirection, 117 180 K kernel kernel kernel kernel kernel kernel kernel critical section, 50 data generation, 142 facilities for real-time, 9 module insertion/removal, 46 scheduling, 39 thread control, 42 thread creating and binding, 149 L latency, 48, 49 libbitmask, 7 libcpuset, 7, 116 libreact, 8 libuli, 98 linkage, 124, 141 Linux requirement, 7 Linux Trace, 127 Linux Trace Toolkit, 128 lk, 8 LOCK_MAND, 20 locking memory, 102 locking virtual memory, 10 low output modes, 34 low-level driver interface, 23 low-level driver template, 31 lspci, 93 M major frame, 56 master controller thread, 79 master scheduler, 79 maximum response time guarantee, 48 mechanism for callout, 29 memory locking, 149 memory locking (virtual), 10 007–4746–014 TM REACT memory nodes assigned to the /boot cpuset, 120 memory requirement, 7 memory-mapped I/O, 91 Message-Passing Interface (MPI), 15 minor frame, 56, 64 mlock(), 10, 100 mlockall(), 10, 100 mmap, 20 mode attribute file, 18 mode switch, 48, 51 modelist attribute file, 18 monitoring trace events, 136 MPI, 15 ms (milliseconds), 3 msync, 91, 92 multiple devices and ULI, 101 multiple independent drivers, 32 multiprocessor architecture, 66 N netlink socket use, 149 new pthreads library (NPTL), 42 nice value, 9 normal-time program, 1 NPTL, 42 O open a user trace routine, 140 operating system requirements, 7 operator, 2 output modes, 34 overhead work, 43 overrun, 5 overrun exception, 64 overrun in frame scheduler, 71 007–4746–014 Real-Time for Linux® Programmer’s Guide P page fault, 10 page fault event, 134 param.h, 40 PCI devices and programmed I/O, 93 PCI-RT-Z, 53 peak data rate, 5 period attribute file, 18 permissions routine, 122 physical ID, 148 physical interfaces, 36 physical memory requirements, 10 poll, 20 POSIX real-time policies, 10 real-time specification 1003.1-2003, 92 power plant simulator, 3 priorities, 39 priority band, 40 problem removing /rtcpus, 148 /proc manipulation, 11 /proc/cpuinfo, 147 /proc/interrupts, 44, 145 process control, 6 process details in tracevisualizer, 137 process mapping to CPU, 10 process running on a real-time CPU, 115 processor requirement, 7 profile.pl, 145 programmed I/O and PCI devices, 93 programming language for REACT, 7 propagation delay, 49 provider attribute file, 19 ps, 41, 145 pthread priority, 42 pthread_attr_setinheritsched(), 42 pthread_attr_setschedparam(), 42 pthread_attr_setschedpolicy(), 42 pthread_attr_t, 42 pthread_attr_t(), 59 181 Index pthread_create(), 42, 78 PTHREAD_EXPLICIT_SCHED, 42 PTHREAD_INHERIT_SCHED, 42 pthread_setschedparam(), 42 pthread_t, 59 pulse output modes, 34 Q RPMs, 7 RT_NO_WAIT, 119, 120 RT_WAIT, 119, 120 RTC, 12 RTC access, 14 rtcpu, 54 rtcpu devices, 107 RTCPUS, 121 RTMEMS, 121 quantum attribute file, 19 S R rate See "frame rate", 3 raw trace, 137 react command, 6 react-permissions.pl, 116 react-utils, 8 read system call, 20 real-time applications, 2 real-time clock (RTC), 12 real-time CPU and running a process, 115 real-time CPUs currently configured on the system, 121 real-time memory nodes associated with the real-time CPUs, 121 real-time priority band, 40 real-time program and frame scheduler, 11 terminology, 1 register access, 14 register format, 35 registration of callout, 29 repeat frame, 82 requirements, 7 response time guarantee, 48 restricting a CPU, 45 RHEL requirement, 7 round-robin, 10 182 sched_setparam(), 40 sched_setscheduler(), 10, 40 scheduler events, 133, 134 scheduling, 39 scheduling disciplines, 9, 71 scheduling policy, 149 select system call, 20 SGI Linux Trace, 6, 127 SGI Linux Trace user library, 139 sgi-extint-kmp-*, 7 sgiioc4 driver, 33 sig_dequeue, 87 sig_overrun, 87 sig_underrun, 87 sig_unframesched, 87 signal, 86 signal handler, 80 SIGRTMIN, 87 SIGUSR1, 87 SIGUSR2, 87 simulator, 2 single frame scheduler start, 66 slave controller thread, 80 slave scheduler, 79 SLES requirement, 7 SLT, 127 See "SGI Linux Trace", 139 slt-cpu.all, 132, 142 007–4746–014 TM REACT slt-cpu.N, 132 slt-cpu.user, 142 SLT-DataFiles, 127 slt_close_utrace, 139, 140 slt_open_utrace, 140 slt_user_trace, 141 sltdebug kernel, 138 SN hub device interrupts, 51 socket programming, 14 soft real-time program, 1 soft-IRQ execution event, 134 software latency, 48, 49 source attribute file, 19 sourcelist attribute file, 19 special scheduling disciplines, 9 stimulator, 2 strace, 41, 145 strobe output modes, 34 sub-buffer size, 130 swapping requirement, 7 sync group, 79 synchronous I/O, 92 /sys/class/extint/extint#/ , 19 /sys/class/ioc4_intout/intout#/dev, 35 sysconf(_SC_CLK_TCK), 13 sysfs attribute files, 18 system call event, 135 system call exit, 135 system configuration generation, 107 system fault event, 133 system-call time base, 55 T tasklet action event, 134 tasklet hiaction, 134 thread, 58 thread control, 42 thread creation, destruction, and signals, 149 thread programming model, 55 time base for frame scheduler, 69 007–4746–014 Real-Time for Linux® Programmer’s Guide time base support, 55 time difference, 137 time estimation, 65 time frame in tracevisualizer, 136 time slices, 40 time-share applications, 10 Timer interrupt control REACT library routine, 118 timer interrupts, 11, 40 timer_create(), 13 toggle output modes, 34 top, 145 Trace, 6 trace data gathering, 129 trace events, 132 trace files and event types, 132 tracedaemon, 127, 131 tracevisualizer, 127, 129, 142 transport delay, 3 troubleshooting, 145 U u_trace_test, 142 ULI See "User-level interrupt (ULI)", 97 uli, 98 ULI_block_intr, 99 ULI_destroy, 98 ULI_register_irq(), 98, 103 ULI_sleep(), 99 ULI_unblock_intr, 99 ULI_wakeup(), 99 unaligned access event, 134 underrun exception, 64 underrun, in frame scheduler, 71 unsupported hardware device capabilities, 31 usecs (microseconds), 48 user access, 116 user application communication, 149 user data generation, 142 183 Index user event generation, 139 user thread control, 42 user thread dispatch, 51 user trace routines, 140 user-level interrupt (ULI) concurrency, 101 global variables, 101 handler interaction, 104 initializing, 101 interrupt handler registration, 103 multiple devices, 101 mutual exclusion, 105 overview, 97 per-IRQ handler, 103 program address space locking, 102 restrictions on handler, 99 ULI_block_intr(), 105 ULI_sleep (), 104 ULI_sleep () function, 101 ULI_wakeup () function, 104 user-level interrupts (ULI), 165 /usr/include/asm/param.h, 40 /usr/include/sn/timer.h, 14 184 /usr/include/sys/pthread.h, 59 /usr/share/src/react/examples, 60 V virtual memory locking, 10 virtual reality simulator, 4 volatile keyword, 101 Vsync time base, 55 W wave stimulator, 5 write bitmask routine, 120 Z zooming in tracevisualizer, 136 007–4746–014
Source Exif Data:
File Type : PDF File Type Extension : pdf MIME Type : application/pdf PDF Version : 1.2 Linearized : Yes Create Date : 2010:09:27 13:20:09-07:00 Modify Date : 2010:09:27 13:20:09-07:00 Page Count : 212 Creation Date : 2010:09:27 20:20:09Z Mod Date : 2010:09:27 20:20:09Z Producer : Acrobat Distiller 5.0 (Windows) Metadata Date : 2010:09:27 20:20:09Z Page Mode : UseOutlinesEXIF Metadata provided by EXIF.tools