Tru64 Unix Programmers Guide
Tru64 Unix Programmers Guide
Programmer’s Guide
August 2000
COMPAQ and the Compaq logo Registered in U.S. Patent and Trademark Office. Alpha and Tru64 are
trademarks of Compaq Information Technologies Group, L.P.
Microsoft and Windows are trademarks of Microsoft Corporation. UNIX and The Open Group are
trademarks of The Open Group. All other product names mentioned herein may be trademarks or
registered trademarks of their respective companies.
Confidential computer software. Valid license from Compaq required for possession, use, or copying.
Consistent with FAR 12.211 and 12.212, Commercial Computer Software, Computer Software
Documentation, and Technical Data for Commercial Items are licensed to the U.S. Government under
vendor’s standard commercial license.
Compaq shall not be liable for technical or editorial errors or omissions contained herein. The information
in this document is subject to change without notice.
THE INFORMATION IN THIS PUBLICATION IS PROVIDED “AS IS” WITHOUT WARRANTY OF ANY
KIND. THE ENTIRE RISK ARISING OUT OF THE USE OF THIS INFORMATION REMAINS WITH
RECIPIENT. IN NO EVENT SHALL COMPAQ BE LIABLE FOR ANY DIRECT, CONSEQUENTIAL,
INCIDENTAL, SPECIAL, PUNITIVE, OR OTHER DAMAGES WHATSOEVER (INCLUDING WITHOUT
LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION OR LOSS
OF BUSINESS INFORMATION), EVEN IF COMPAQ HAS BEEN ADVISED OF THE POSSIBILITY
OF SUCH DAMAGES AND WHETHER IN AN ACTION OF CONTRACT OR TORT, INCLUDING
NEGLIGENCE.
The limited warranties for Compaq products are exclusively set forth in the documentation accompanying
such products. Nothing herein should be construed as constituting a further or additional warranty.
Contents
1 Overview
1.1 Application Development Phases .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 1–1
1.2 Specification and Design Considerations .. . .. . .. . .. . . .. . .. . .. . .. . 1–2
1.2.1 Standards . . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 1–2
1.2.2 Internationalization .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 1–3
1.2.3 Window-Oriented Applications .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 1–3
1.2.4 Secure Applications . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 1–4
1.3 Major Software Development Tools .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 1–4
1.3.1 Languages Supported by the Tru64 UNIX Environment . . 1–4
1.3.2 Linking Object Files .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 1–4
1.3.3 Debugging and Program Analysis Tools .. . .. . .. . . .. . .. . .. . .. . 1–5
1.4 Source File Control .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 1–5
1.5 Program Installation Tools . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 1–6
1.6 Overview of Interprocess Communication Facilities .. . .. . .. . .. . 1–7
Contents iii
2.5 Linking Object Files . . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–19
2.5.1 Linking with Compiler Commands . . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–20
2.5.2 Linking with the ld Command . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–20
2.5.3 Specifying Libraries .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–21
2.6 Running Programs . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–22
2.7 Object File Tools . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–23
2.7.1 Dumping Selected Parts of Files (odump) . .. . .. . . .. . .. . .. . .. . 2–24
2.7.2 Listing Symbol Table Information (nm) .. . .. . .. . . .. . .. . .. . .. . 2–24
2.7.3 Determining a File’s Type (file) .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–25
2.7.4 Determining a File’s Segment Sizes (size) .. . .. . . .. . .. . .. . .. . 2–25
2.7.5 Disassembling an Object File (dis) . . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–26
2.8 ANSI Name Space Pollution Cleanup in the Standard C
Library . . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–26
2.9 Inline Assembly Code — ASMs . . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–28
iv Contents
4 Shared Libraries
4.1 Shared Library Overview . . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–1
4.2 Resolving Symbols . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–3
4.2.1 Search Path of the Linker .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–4
4.2.2 Search Path of the Run-time Loader . .. . .. . .. . .. . . .. . .. . .. . .. . 4–4
4.2.3 Name Resolution . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–5
4.2.4 Options to Determine Handling of Unresolved External
Symbols . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–6
4.3 Linking with Shared Libraries . . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–7
4.4 Turning Off Shared Libraries . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–7
4.5 Creating Shared Libraries . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–8
4.5.1 Creating Shared Libraries from Object Files .. . . .. . .. . .. . .. . 4–8
4.5.2 Creating Shared Libraries from Archive Libraries .. . .. . .. . 4–8
4.6 Working with Private Shared Libraries . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–8
4.7 Using Quickstart .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–9
4.7.1 Verifying That an Object Is Quickstarting .. . .. . . .. . .. . .. . .. . 4–11
4.7.2 Manually Tracking Down Quickstart Problems . .. . .. . .. . .. . 4–12
4.7.3 Tracking Down Quickstart Problems with the fixso
Utility . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–14
4.8 Debugging Programs Linked with Shared Libraries .. . .. . .. . .. . 4–15
4.9 Loading a Shared Library at Run Time . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–15
4.10 Protecting Shared Library Files . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–17
4.11 Shared Library Versioning . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–17
4.11.1 Binary Incompatible Modifications . . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–18
4.11.2 Shared Library Versions . . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–19
4.11.3 Major and Minor Versions Identifiers .. . .. . .. . .. . . .. . .. . .. . .. . 4–21
4.11.4 Full and Partial Versions of Shared Libraries . . . .. . .. . .. . .. . 4–22
4.11.5 Linking with Multiple Versions of Shared Libraries . .. . .. . 4–22
4.11.6 Version Checking at Load Time .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–24
4.11.7 Multiple Version Checking at Load Time . . .. . .. . . .. . .. . .. . .. . 4–25
4.12 Symbol Binding . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–30
4.13 Shared Library Restrictions .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–30
Contents v
5.2 Running dbx . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–6
5.2.1 Compiling a Program for Debugging . .. . .. . .. . .. . . .. . .. . .. . .. . 5–6
5.2.2 Creating a dbx Initialization File . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–7
5.2.3 Invoking and Terminating dbx . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–7
5.3 Using dbx Commands .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–9
5.3.1 Qualifying Variable Names . . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–9
5.3.2 dbx Expressions and Their Precedence . .. . .. . .. . . .. . .. . .. . .. . 5–10
5.3.3 dbx Data Types and Constants . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–10
5.4 Working with the dbx Monitor .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–12
5.4.1 Repeating dbx Commands .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–12
5.4.2 Editing the dbx Command Line .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–13
5.4.3 Entering Multiple Commands . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–14
5.4.4 Completing Symbol Names . . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–15
5.5 Controlling dbx . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–15
5.5.1 Setting and Removing Variables . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–15
5.5.2 Predefined dbx Variables . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–17
5.5.3 Defining and Removing Aliases .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–23
5.5.4 Monitoring Debugging Session Status . . .. . .. . .. . . .. . .. . .. . .. . 5–24
5.5.5 Deleting and Disabling Breakpoints . .. . .. . .. . .. . . .. . .. . .. . .. . 5–25
5.5.6 Displaying the Names of Loaded Object Files . . . .. . .. . .. . .. . 5–26
5.5.7 Specifying the Location of Shared Libraries for Core
Dumps .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–26
5.5.8 Invoking a Subshell from Within dbx .. . .. . .. . .. . . .. . .. . .. . .. . 5–27
5.6 Examining Source Programs . . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–27
5.6.1 Specifying the Locations of Source Files .. . .. . .. . . .. . .. . .. . .. . 5–27
5.6.2 Moving Up or Down in the Activation Stack . .. . . .. . .. . .. . .. . 5–28
5.6.2.1 Using the where and tstack Commands . .. . . .. . .. . .. . .. . 5–28
5.6.2.2 Using the up, down, and func Commands . . . .. . .. . .. . .. . 5–29
5.6.3 Changing the Current Source File . . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–30
5.6.4 Listing Source Code . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–30
5.6.5 Searching for Text in Source Files .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–31
5.6.6 Editing Source Files from Within dbx . . .. . .. . .. . . .. . .. . .. . .. . 5–32
5.6.7 Identifying Variables That Share the Same Name .. . .. . .. . 5–32
5.6.8 Examining Variable and Procedure Types .. . .. . . .. . .. . .. . .. . 5–33
5.7 Controlling the Program .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–33
5.7.1 Running and Rerunning the Program . . .. . .. . .. . . .. . .. . .. . .. . 5–33
5.7.2 Executing the Program Step by Step .. . .. . .. . .. . . .. . .. . .. . .. . 5–35
5.7.3 Using the return Command . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–36
5.7.4 Going to a Specific Place in the Code .. . .. . .. . .. . . .. . .. . .. . .. . 5–36
5.7.5 Resuming Execution After a Breakpoint . . .. . .. . . .. . .. . .. . .. . 5–37
5.7.6 Changing the Values of Program Variables . . .. . . .. . .. . .. . .. . 5–38
5.7.7 Patching Executable Disk Files .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–38
vi Contents
5.7.8 Running a Specific Procedure . . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–39
5.7.9 Setting Environment Variables .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–40
5.8 Setting Breakpoints . . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–40
5.8.1 Overview .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–41
5.8.2 Setting Breakpoints with stop and stopi . . .. . .. . . .. . .. . .. . .. . 5–41
5.8.3 Tracing Variables During Execution . .. . .. . .. . .. . . .. . .. . .. . .. . 5–43
5.8.4 Writing Conditional Code in dbx . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–45
5.8.5 Catching and Ignoring Signals . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–46
5.9 Examining Program State . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–47
5.9.1 Printing the Values of Variables and Expressions . .. . .. . .. . 5–47
5.9.2 Displaying Activation-Level Information with the dump
Command .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–49
5.9.3 Displaying the Contents of Memory . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–50
5.9.4 Recording and Playing Back Portions of a dbx Session . .. . 5–51
5.9.4.1 Recording and Playing Back Input . .. . .. . .. . . .. . .. . .. . .. . 5–51
5.9.4.2 Recording and Playing Back Output . . .. . .. . . .. . .. . .. . .. . 5–53
5.10 Enabling Core-Dump File Naming . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–54
5.10.1 Enabling Core-File Naming at the System Level . . .. . .. . .. . 5–55
5.10.2 Enabling Core-File Naming at the Application Level .. . .. . 5–55
5.11 Debugging a Running Process .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–55
5.12 Debugging Multithreaded Applications . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–57
5.13 Debugging Multiple Asynchronous Processes . .. . .. . . .. . .. . .. . .. . 5–60
5.14 Sample Program .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–61
Contents vii
6.7.2 Bit Field Uses . . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 6–11
6.7.3 External Name Size .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 6–11
6.7.4 Multiple Uses and Side Effects .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 6–12
6.8 Checking for Coding Errors and Coding Style Differences . . .. . 6–12
6.8.1 Assignments of Long Variables to Integer Variables . .. . .. . 6–13
6.8.2 Operator Precedence .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 6–13
6.8.3 Conflicting Declarations . . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 6–13
6.9 Increasing Table Size . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 6–13
6.10 Creating a lint Library . . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 6–14
6.10.1 Creating the Input File . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 6–14
6.10.2 Creating the lint Library File . . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 6–15
6.10.3 Checking a Program with a New Library . .. . .. . . .. . .. . .. . .. . 6–16
6.11 Understanding lint Error Messages . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 6–16
6.12 Using Warning Class Options to Suppress lint Messages .. . .. . 6–21
6.13 Generating Function Prototypes for Compile-Time Detection
of Syntax Errors . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 6–25
viii Contents
8 Profiling Programs to Improve Performance
8.1 Profiling Sample Program . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–2
8.2 Compilation Options for Profiling . . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–4
8.3 Manual Design and Code Optimizations . .. . .. . .. . .. . . .. . .. . .. . .. . 8–4
8.3.1 Techniques . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–4
8.3.2 Tools and Examples . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–5
8.3.2.1 CPU-Time Profiling with Call Graph . .. . .. . . .. . .. . .. . .. . 8–5
8.3.2.1.1 Using the hiprof Profiler . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–5
8.3.2.1.2 Using the cc Command’s -pg Option . .. . . .. . .. . .. . .. . 8–10
8.3.2.2 CPU−Time/Event Profiles for Sourcelines/Instruc-
tions . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–11
8.3.2.2.1 Using the uprofile Profiler . . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–12
8.3.2.2.2 Using the hiprof Profiler . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–15
8.3.2.2.3 Using the cc Command’s -p Option . . .. . . .. . .. . .. . .. . 8–16
8.3.2.2.4 Using the pixie Profiler .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–18
8.4 Minimizing System Resource Usage . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–20
8.4.1 Techniques . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–20
8.4.2 Tools and Examples . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–21
8.4.2.1 System Monitors .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–21
8.4.2.2 Heap Memory Analyzers .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–21
8.5 Verifying the Significance of Test Cases . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–23
8.5.1 Techniques . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–23
8.5.2 Tools and Examples . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–24
8.6 Selecting Profiling Information to Display . . .. . .. . .. . . .. . .. . .. . .. . 8–24
8.6.1 Limiting Profiling Display to Specific Procedures . .. . .. . .. . 8–25
8.6.2 Displaying Profiling Information for Each Source Line . .. . 8–25
8.6.3 Limiting Profiling Display by Line . . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–26
8.6.4 Including Shared Libraries in the Profiling Information . . 8–26
8.6.4.1 Specifying the Location of Instrumented Shared
Libraries .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–27
8.7 Merging Profile Data Files . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–27
8.7.1 Data File-Naming Conventions .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–27
8.7.2 Data File-Merging Techniques . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–28
8.8 Profiling Multithreaded Applications . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–29
8.9 Using monitor Routines to Control Profiling . . .. . .. . . .. . .. . .. . .. . 8–30
Contents ix
9.1.3 Atom Options . . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–4
9.2 Developing Atom Tools . . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–6
9.2.1 Atom’s View of an Application . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–6
9.2.2 Atom Instrumentation Routine .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–7
9.2.3 Atom Instrumentation Interfaces .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–8
9.2.3.1 Navigating Within a Program .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–8
9.2.3.2 Building Objects .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–9
9.2.3.3 Obtaining Information About an Application’s
Components . . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–9
9.2.3.4 Resolving Procedure Names and Call Targets . .. . .. . .. . 9–12
9.2.3.5 Adding Calls to Analysis Routines to a Program . .. . .. . 9–13
9.2.4 Atom Description File . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–14
9.2.5 Writing Analysis Procedures .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–14
9.2.5.1 Input/Output . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–15
9.2.5.2 fork and exec System Calls .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–15
9.2.6 Determining the Instrumented PC from an Analysis
Routine . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–16
9.2.7 Sample Tools .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–22
9.2.7.1 Procedure Tracing . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–22
9.2.7.2 Profile Tool .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–25
9.2.7.3 Data Cache Simulation Tool . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–28
10 Optimizing Techniques
10.1 Guidelines to Build an Application Program . . .. . .. . . .. . .. . .. . .. . 10–2
10.1.1 Compilation Considerations . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 10–2
10.1.2 Linking and Loading Considerations .. . .. . .. . .. . . .. . .. . .. . .. . 10–6
10.1.3 Spike and Profile-Directed Optimization . . .. . .. . . .. . .. . .. . .. . 10–6
10.1.3.1 Overview of spike . . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 10–6
10.1.3.2 Using spike for Profile-Directed Optimization . .. . .. . .. . 10–8
10.1.4 Preprocessing and Postprocessing Considerations . .. . .. . .. . 10–11
10.1.5 Library Routine Selection . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 10–12
10.2 Application Coding Guidelines .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 10–13
10.2.1 Data-Type Considerations .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 10–14
10.2.2 Using Direct I/O on AdvFS Files . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 10–14
10.2.3 Cache Usage and Data Alignment Considerations .. . .. . .. . 10–16
10.2.4 General Coding Considerations .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 10–17
x Contents
11.1.3 Header Files That Support Exception Handling .. . .. . .. . .. . 11–3
11.2 Raising an Exception from a User Program .. . .. . .. . . .. . .. . .. . .. . 11–4
11.3 Writing a Structured Exception Handler .. . .. . .. . .. . . .. . .. . .. . .. . 11–5
11.4 Writing a Termination Handler . . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 11–12
Contents xi
13.6.2.3 Atom and OpenMP Tools .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 13–13
13.6.2.4 Other Debugging Aids .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 13–13
xii Contents
14.7.10 Using Event Filters . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–31
14.7.11 Sample EVM Programming Operations .. . .. . .. . . .. . .. . .. . .. . 14–31
14.7.11.1 Performing Simple Event Manipulations .. . . .. . .. . .. . .. . 14–32
14.7.11.2 Using Variable-Length Argument Lists . .. . . .. . .. . .. . .. . 14–33
14.7.11.3 Adding and Retrieving Variables .. . .. . .. . .. . . .. . .. . .. . .. . 14–35
14.7.11.4 Posting Events . . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–37
14.7.11.5 Reading and Writing Events . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–39
14.7.11.6 Subscribing for Event Notification . .. . .. . .. . . .. . .. . .. . .. . 14–41
14.7.11.7 Handling Multiple I/O Sources . . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–44
14.7.11.8 Using Filter Evaluators . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–47
14.7.11.9 Matching Event Names . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–50
14.7.11.10 Dealing with Missed Events . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–51
14.8 Adding an Event Channel to EVM . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–54
14.8.1 The Get Function . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–55
14.8.2 The Details Function . . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–58
14.8.3 The Explain Function . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–58
14.8.4 The Monitor Function . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–59
14.8.5 The Cleanup Function . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–60
14.8.6 Channel Security . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–61
Contents xiii
C.2.2 Example Definition Attribute Table . . .. . .. . .. . .. . . .. . .. . .. . .. . C–8
C.2.3 Communication Attribute Table . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . C–10
C.2.4 Example Communication Attribute Table .. . .. . . .. . .. . .. . .. . C–11
C.3 Creating a Configuration Routine . . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . C–12
C.3.1 Performing Initial Configuration . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . C–13
C.3.2 Responding to Query Requests .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . C–15
C.3.3 Responding to Reconfigure Requests .. . .. . .. . .. . . .. . .. . .. . .. . C–17
C.3.4 Performing Subsystem-Defined Operations . .. . . .. . .. . .. . .. . C–20
C.3.5 Unconfiguring the Subsystem . . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . C–20
C.3.6 Returning from the Configuration Routine . . .. . . .. . .. . .. . .. . C–21
C.4 Allowing for Operating System Revisions in Loadable
Subsystems . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . C–22
C.5 Building and Loading Loadable Subsystems . . .. . .. . . .. . .. . .. . .. . C–23
C.6 Building a Static Configurable Subsystem Into the Kernel . .. . C–24
C.7 Testing Your Subsystem .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . C–27
xiv Contents
Index
Examples
5–1 Sample Program Used in dbx Examples . .. . .. . .. . .. . . .. . .. . .. . .. . 5–61
8–1 Profiling Sample Program . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–2
8–2 Sample hiprof Default Profile Using gprof . . .. . .. . .. . . .. . .. . .. . .. . 8–6
8–3 Sample hiprof -cycles Profile Using gprof .. . .. . .. . .. . . .. . .. . .. . .. . 8–8
8–4 Sample cc -pg Profile Using gprof . . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–10
8–5 Sample uprofile CPU-Time Profile Using prof .. . .. . . .. . .. . .. . .. . 8–12
8–6 Sample uprofile Data-Cache-Misses Profile Using prof .. . .. . .. . 8–14
8–7 Sample hiprof -lines PC-Sampling Profile . . .. . .. . .. . . .. . .. . .. . .. . 8–15
8–8 Sample cc -p Profile Using prof . . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–17
8–9 Sample pixie Profile Using prof . . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–19
8–10 Sample third Log File .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–22
8–11 Using monstartup() and monitor() . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8–31
8–12 Allocating Profiling Buffers Within a Program . . .. . . .. . .. . .. . .. . 8–32
8–13 Using monitor_signal() to Profile Nonterminating Programs . . 8–34
10–1 Pointers and Optimization . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 10–20
11–1 Handling a SIGSEGV Signal as a Structured Exception . .. . .. . 11–7
11–2 Handling an IEEE Floating-Point SIGFPE as a Structured
Exception . . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 11–9
11–3 Multiple Structured Exception Handlers .. . .. . .. . .. . . .. . .. . .. . .. . 11–11
11–4 Abnormal Termination of a Try Block by an Exception .. . .. . .. . 11–15
12–1 Threads Programming Example . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 12–6
14–1 Sample Event Explanation Text . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–19
14–2 Performing Simple Event Manipulations .. . .. . .. . .. . . .. . .. . .. . .. . 14–32
14–3 Using Variable-Length Argument Lists . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–34
14–4 Adding and Retrieving Variables .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–35
14–5 Posting Events . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–38
14–6 Reading and Writing Events . . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–40
14–7 Subscribing for Event Notification . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–42
14–8 Handling Multiple I/O Sources . . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–45
14–9 Using Filter Evaluators . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–48
14–10 Matching Event Names . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–51
14–11 Dealing with Missed Events . . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–52
C–1 Example Attribute Table . . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . C–8
Figures
2–1 Compiling a Program . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–2
Contents xv
2–2 Default Structure Alignment . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–6
2–3 Default Bit-Field Alignment . . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–7
2–4 Padding to the Next Pack Boundary . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–8
4–1 Use of Archive and Shared Libraries . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–3
4–2 Linking with Multiple Versions of Shared Libraries .. . .. . .. . .. . 4–23
4–3 Invalid Multiple Version Dependencies Among Shared
Objects: Example 1 .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–26
4–4 Invalid Multiple Version Dependencies Among Shared
Objects: Example 2 .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–27
4–5 Invalid Multiple Version Dependencies Among Shared
Objects: Example 3 .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–28
4–6 Valid Uses of Multiple Versions of Shared Libraries: Example
1 . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–29
4–7 Valid Uses of Multiple Versions of Shared Libraries: Example
2 . . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 4–30
14–1 EVM Overview . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–4
14–2 Posted Event and Template Merging . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–23
A–1 Layout of Memory Under -taso Option . . . .. . .. . .. . .. . . .. . .. . .. . .. . A–5
B–1 System Call Resolution . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . B–2
C–1 System Attribute Value Initialization .. . . .. . .. . .. . .. . . .. . .. . .. . .. . C–3
Tables
1–1 Programming Phases and Tru64 UNIX . . .. . .. . .. . .. . . .. . .. . .. . .. . 1–1
2–1 Compiler System Functions .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–2
2–2 File Suffixes and Associated Files . . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–3
2–3 cc Command Default Options, by Option Category . . .. . .. . .. . .. . 2–15
3–1 Intrinsic Functions .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 3–14
4–1 Linker Options That Control Shared Library Versioning .. . .. . 4–20
5–1 Keywords Used in Command Syntax Descriptions . . .. . .. . .. . .. . 5–2
5–2 dbx Command Options . . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–8
5–3 The dbx Number-Sign Expression Operator .. . .. . .. . . .. . .. . .. . .. . 5–10
5–4 Expression Operator Precedence .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–10
5–5 Built-in Data Types .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–11
5–6 Input Constants . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–11
5–7 Command-Line Editing Commands in emacs Mode . .. . .. . .. . .. . 5–13
5–8 Predefined dbx Variables . . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 5–17
5–9 Modes for Displaying Memory Addresses .. . .. . .. . .. . . .. . .. . .. . .. . 5–50
6–1 lint Warning Classes . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 6–23
9–1 Example Prepackaged Atom Tools . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–2
9–2 Atom Object Query Routines . . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–10
9–3 Atom Procedure Query Routines .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–11
9–4 Atom Basic Block Query Routines . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–12
xvi Contents
9–5 Atom Instruction Query Routines . . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 9–12
11–1 Header Files That Support Exception Handling . .. . . .. . .. . .. . .. . 11–3
14–1 Standard Data Items . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–7
14–2 Substituting Variables into Event Text . . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–13
14–3 EVM’s Variable Data Types .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–16
14–4 Name Matching Examples . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 14–22
14–5 Example Data Item Values for an Internationalized Event .. . 14–25
B–1 System Call Summary . . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . B–4
B–2 Library Function Summary .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . B–5
C–1 Attribute Data Types . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . C–6
C–2 Codes That Determine the Requests Allowed for an Attribute C–7
C–3 Attribute Status Codes . . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . C–11
Contents xvii
About This Manual
Audience
This manual addresses all programmers who use the Tru64 UNIX operating
system to create or maintain programs in any supported language.
Organization
This manual contains 14 chapters and 6 appendixes.
Related Documents
In addition to this manual, the following manuals contain information
pertaining to program development:
Programming: General
Calling Standard for Alpha Systems
Assembly Language Programmer’s Guide
Programming Support Tools
Network Programmer’s Guide
Compaq Portable Mathematics Library
Writing Software for the International Market
Kernel Debugging
Ladebug Debugger Manual
Writing Kernel Modules
Alpha Architecture Reference Manual, 2nd Edition (Butterworth-Hinemann
Press, ISBN:1–55558–145–5)
Programming: Realtime
Guide to Realtime Programming
Programming: Streams
Programmer’s Guide: STREAMS
Programming: Multithreaded Applications
Some books in the documentation help meet the needs of several audiences.
For example, the information in some system books is also used by
programmers. Keep this in mind when searching for information on specific
topics.
The Documentation Overview provides information on all of the books in
the Tru64 UNIX documentation set.
Reader’s Comments
Compaq welcomes any comments and suggestions you have on this and
other Tru64 UNIX manuals.
You can send your comments in the following ways:
• Fax: 603-884-0120 Attn: UBPG Publications, ZKO3-3/Y32
• Internet electronic mail: readers_comment@zk3.dec.com
A Reader’s Comment form is located on your system in the following
location:
/usr/doc/readers_comment.txt
• Mail:
Compaq Computer Corporation
UBPG Publications Manager
ZKO3-3/Y32
Conventions
%
$ A percent sign represents the C shell system prompt.
A dollar sign represents the system prompt for the
Bourne, Korn, and POSIX shells.
[|]
{|} In syntax definitions, brackets indicate items that
are optional and braces indicate items that are
required. Vertical bars separating items inside
brackets or braces indicate that you choose one item
from among those listed.
In many instances, the Tru64 UNIX system offers more than one tool to do a
job. The choices of tools and programming languages to use are left to you.
Overview 1–1
1.2 Specification and Design Considerations
When you design an application, some of your decisions depend on the nature
of the application. Tru64 UNIX provides features and tools to help you
create applications that can be portable, internationalized, window-oriented,
or whatever is appropriate for the needs of the users of those applications.
One of the primary design considerations concerns adhering to UNIX
environment standards and portability. If you want your application to
run both on Tru64 UNIX systems and on other UNIX operating systems,
consider limiting your design to features that adhere to X/Open portability
guidelines and POSIX standards.
You might also need to design your application so that it can be used
in a variety of countries. The Tru64 UNIX operating system contains
internationalization tools and functions to help you write software to be used
by people working in different natural languages.
Another consideration is the terminal environment in which your application
will be used. If end users have workstations or window terminals, you might
want to design your application to use window displays.
1.2.1 Standards
Adhering to programming standards enhances the ability to port programs
and applications between hardware platforms or even operating systems.
Writing programs according to portability standards makes it easy for users
to move between systems without major retraining. As part of program
portability, some standards include internationalization concepts.
The following are the primary standards in the UNIX programming
environment:
• ANSI
• ISO
• POSIX
• X/Open
In addition to the standards in the preceding list, the OSF Application
Environment Specification (AES) specifies application-level interfaces
that an application must provide to support portable applications and the
semantics or protocols associated with these interfaces.
Various ANSI standards apply to specific programming tools such as
languages, networks and communication protocols, character coding,
and database systems. Information on conformance and extensions to
a particular ANSI standard appears in the documentation set for the
1–2 Overview
particular language, network system, or database system. For information
about compiling C programs to adhere to ANSI standards, see Chapter 2.
The Tru64 UNIX system allows you to write programs that conform to
POSIX and X/Open standards. Information on the POSIX standard is
contained in POSIX — Part 1: System Application Program Interface (API)
[C Language] for IEEE Std. 1003.1c-1994. The Tru64 UNIX header files
contain POSIX and X/Open conformant information.
1.2.2 Internationalization
An internationalized application provides a run-time interface that
allows users to work in their own language with culturally appropriate
representations of data. The Tru64 UNIX operating system provides
interfaces and utilities for you to develop internationalized applications that
conform to Issue 4 of the X/Open CAE specifications. It also supports the
Multibyte Support Extension (MSE) of ISO C that is part of Issue 5 of the
X/Open CAE specifications.
Considerations for developing internationalized applications include:
• Language
• Cultural data
• Character sets
• Localization
To meet these considerations, your applications must not make any
assumptions about language, local customs, or coded character sets. Data
specific to a culture is held separate from the application’s logic. You use
run-time facilities to bind your application to the appropriate language
message text.
For details about the Tru64 UNIX internationalization package, see Writing
Software for the International Market.
Overview 1–3
Common Desktop Environment: Style Guide and Certification Checklist
Common Desktop Environment: Help System Author’s and Programmer’s
Guide
For more information on the assembler, see as(1) and the Assembly
Language Programmer’s Guide.
You can order documentation for the other languages when you order the
compilers for those languages.
1–4 Overview
In addition, the linker resolves external references, searches libraries, and
performs all other processing required to create an executable object file.
The development environment allows you to create applications composed
of source code files written in different languages. In these instances, you
compile each of the files separately and then link the compiled object files
together in a separate step. You invoke the linker separately from the
compiler by entering the ld command.
You can create shared libraries by using compiler driver commands or the
ld command. In addition, you can create archive (static) libraries by using
the ar command. For more information on how to create libraries, see
Chapter 4. For detailed information on compiling and linking programs,
see Chapter 2 and Chapter 4, as well as the documentation sets for the
individual languages.
Overview 1–5
SCCS and RCS maintain a record of changes made to files stored using the
utility. The record can include information on why the changes were made,
who made them, and when they were made. You can use either SCCS or
RCS to recover previous versions of files as well as to maintain different
versions simultaneously. SCCS is useful for application project management
because it does not allow two people to modify the same file simultaneously.
For more information , see sccs(1), rcs(1), and the Programming Support
Tools manual.
1–6 Overview
Using setld, you can load your application on any of the following
distribution media for installation on other systems:
• CD-ROM distribution media
• An arbitrary, mountable file system on any supported data disk; for
example, a third-party SCSI disk cartridge
For more information on using the setld command and creating and
managing software product kits, see the Programming Support Tools
manual.
Overview 1–7
2
The Compiler System
.i .o a.out
ZK-1079U-AI
short s1 char c1
63 float f 32
char c2
64
71
ZK-1082U-AI
The first component of the structure, c1, starts at offset 0 and occupies the
first byte. The second component, s1, is a short; it must start on a word
boundary. Therefore, padding is added between c1 and s1. No padding is
needed to make f and c2 fall on their natural boundaries. However, because
size is rounded up to a multiple of f’s alignment, three bytes of padding are
added after c2.
You can use the following mechanisms to override the default alignment of
structure members:
• The #pragma member_alignment and #pragma nomember_align-
ment directives
• The #pragma pack directive
• The −Zpn option
See Section 3.8 and Section 3.11 for information on these directives.
short f1
char f2 char f0
ZK-1080U-AI
The first bit field, f0, starts on bit offset 0 and occupies 1 bit. The second,
f1, starts at offset 1 and occupies 12 bits. The third, f2, starts at offset 13
and occupies 3 bits. The size of the structure is two bytes.
Certain conditions can cause padding to occur prior to the alignment of the
bit field:
• Bit fields of size 0 cause padding to the next pack boundary. (The pack
boundary is determined by the #pragma pack directive or the −Zpn
compiler option.) For bit fields of size 0, the bit field’s base type is
ignored. For example, consider the following structure:
struct b {
char f0: 1;
int : 0;
char f1: 2;
} struct_b;
If the source file is compiled with the −Zp1 option or if a #pragma pack 1
directive is encountered in the compilation, f0 would start at offset 0 and
occupy 1 bit, the unnamed bit field would start at offset 8 and occupy 0
bits, and f1 would start at offset 8 and occupy 2 bits.
Similarly, if the −Zp2 option or the #pragma pack 2 directive were
used, the unnamed bit field would start at offset 16. With −Zp4 or
#pragma pack 4, it would start at offset 32.
• If the bit field does not fit in the current unit, padding occurs to either
the next pack boundary or the next unit boundary, whichever is closest.
(The unit boundary is determined by the bit field’s base type; for
example, the unit boundary associated with the declaration “char foo:
1” is a byte.) The current unit is determined by the current offset, the
bit field’s base size, and the kind of packing specified, as shown in the
following example:
struct c {
char f0: 7;
short f1: 11;
} struct_c;
short f1 char f0
ZK-1081U-AI
The type of source file and the type of standards you apply determine
the macros that are defined. The C compiler supports several levels of
standardization:
• The −std option enforces the ANSI C standard, but allows some common
programming practices disallowed by the standard, and defines the
macro _ _STDC_ _ to be 0 (zero). This is the default.
• The −std0 option enforces the Kernighan and Ritchie (K & R)
programming style, with certain ANSI extensions in areas where the
K & R behavior is undefined or ambiguous. In general, −std0 compiles
most pre-ANSI C programs and produces expected results. It does not
define the _ _STDC_ _ macro.
• The −std1 option strictly enforces the ANSI C standard and all of its
prohibitions (such as those that apply to handling a void, the definition
of an lvalue in expressions, the mixing of integrals and pointers, and
the modification of an rvalue). It defines the _ _STDC_ _ macro to be 1.
You can include header files in a program source file in one of two ways:
#include "filename"
This indicates that the C macro preprocessor should first search for the
include file filename in the directory in which it found the file that
contains the directive, then in the search path indicated by the −I
options, and finally in /usr/include.
#include <filename>
This indicates that the C macro preprocessor should search for the
include file filename in the search path indicated by the −I options
and then in /usr/include, but not in the directory where it found the
file that contains the directive.
You can also use the −Idir and -nocurrent_include options to specify
additional pathnames (directories) to be searched by the C preprocessor for
#include files:
• For -Idir, the C preprocessor searches first in the directory where
it found the file that contains the directive, followed by the specified
pathname (dir), and then the default directory (/usr/include). If dir
is omitted, the default directory is not searched.
• For -I with no arguments, the C preprocessor does not search in
/usr/include.
• For -nocurrent_include, the C preprocessor does not search the
directory containing the file that contains the #include directive;
that is, #include "filename" is treated the same as #include
<filename>.
When the compiler includes this file in a C source file, the _ _LANGUAGE_C_ _
macro is defined and the C code is compiled. When the compiler includes
this file in an assembly language source file, the _ _LANGUAGE_ASSEMBLY_ _
macro is defined, and the assembly language code is compiled.
This command runs the C compiler, creating object files prog1.o and
prog2.o and the executable program a.out.
When you enter the cc compiler command with no other options, the
following options are in effect:
-noansi_alias
Turns off ANSI C aliasing rules, which prevents the optimizer from
being aggressive in its optimizations.
-arch generic
Generates instructions that are appropriate for all Alpha™ processors.
-assume aligned_objects
Allows the compiler to make such an assumption, and thereby generate
more efficient code for pointer dereferences of aligned pointer types.
-call_shared
Produces a dynamic executable file that uses shareable objects at run
time.
-nocheck_bounds
Disables the run-time checking of array bounds.
-cpp
Causes the C macro preprocessor to be called on C and assembly source
files before compiling.
-error_limit 30
Limits the number of error-level diagnostics that the compiler will
output for a given compilation to 30.
-float
Informs the compiler that it is not necessary to promote expressions of
type float to type double.
-nofp_reorder
Directs the compiler not to reorder floating-point computations in a
way that might affect accuracy.
-fprm n
Performs normal rounding (unbiased round to nearest) of floating-point
numbers.
-fptm n
Generates instructions that do not generate floating-point underflow or
inexact trapping modes.
-g0
Does not produce symbol information for symbolic debugging.
-inline manual
Inlines only those function calls explicitly requested for inlining by a
#pragma inline directive.
-intrinsics
Directs the compiler to recognize certain functions as intrinsics and
perform appropriate optimizations.
-member_alignment
Directs the compiler to naturally align data structure members (with
the exception of bit-field members).
-nomisalign
Generates alignment faults for arbitrarily aligned addresses.
-nestlevel=50
Sets the nesting level limit for include files to 50.
-newc
Invokes the compiler with all of the default option settings listed. This
option is provided only to turn off -migrate.
-O1
Enables global optimizations.
-p0
Disables profiling.
-nopg
Turns off gprof profiling.
-preempt_module
Allows symbol preemption on a module-by-module basis.
-signed
Causes type char to use the same representation as signed char.
-std
Enforces the ANSI C standard, but allows some common programming
practices disallowed by the standard.
-tune generic
Selects instruction tuning that is appropriate for all implementations
of the Alpha architecture.
-writable_strings
Makes string literals writable.
Table 2–3 lists the default options according to the option categories used
in cc(1).
This command produces the object file main.o, not the executable file a.out.
After creating object modules for source files written in languages other
than C, you can use the cc command to compile C source files and link all
of the object modules into an executable file. For example, the following cc
command compiles c-prog.c and links c-prog.o and nonc-prog.o into
the executable file a.out:
% cc nonc-prog.o c-prog.c
In this case, the use of &a[10] is allowed even though a[10] is outside
the bounds of the array.
• If the array is being accessed using pointer addition, the check is for
whether the value being added is between zero and the number of
elements in the array inclusive. Adding an integer to an array name
involves converting the array name to a pointer to the first element
and adding the integer value scaled by the size of an element. The
implementation of bounds checking in the compiler is triggered by the
conversion of the array name to a pointer, but at the point in time when
the bounds check is introduced, it is not known whether the resulting
The -lm option specifies the math library; the -lexc option specifies the
exception library.
Compile and link modules with a single command when you want to optimize
your program. Most compilers support increasing levels of optimization with
the use of certain options. For example:
• The -O0 option requests no optimization (usually for debugging
purposes).
• The -O1 option requests certain local (module-specific) optimizations.
• Cross-module optimizations must be requested with the -ifo option.
Specifying -O3 in addition to -ifo improves the quality of cross-module
optimization. In this case, compiling multiple files in one operation
allows the compiler to perform the maximum possible optimizations. The
-ifo option produces one .o file for multiple source files.
/usr/shlib
/usr/ccs/lib
/usr/lib/cmplrs/cc
/usr/lib
For a list of the libraries that each language uses, see the reference pages
of the compiler drivers for the various languages.
• When storing object files in an archive library
You must include the pathname of the library on the compiler or linker
command line. For example, the following command specifies that the
libfft.a archive library in the /usr/jones directory is to be linked
along with the math library:
% cc main.o more.o rest.o /usr/jones/libfft.a -lm
The linker searches libraries in the order that you specify. Therefore, if
any file in your archive library uses data or procedures from the math
library, you must specify the archive library before you specify the math
library.
When the program is invoked, the main function in a C program can accept
arguments from the command line if the main function is defined with one
or more of the following optional parameters:
int main ( int argc, char *argv[ ], char *envp[ ] )[...]
The argc parameter is the number of arguments in the command line that
invoked the program. The argv parameter is an array of character strings
containing the arguments. The envp parameter is the environment array
containing process information, such as the user name and controlling
terminal. (The envp parameter has no bearing on passing command-line
arguments. Its primary use is during exec and getenv function calls.)
You can access only the parameters that you define. For example, the
following program defines the argc and argv parameters to echo the values
of parameters passed to the program:
/*
* Filename: echo-args.c
* This program echoes command-line arguments.
#include <stdio.h>
return(0);
}
The program is compiled with the following command to produce a program
file called a.out:
$ cc echo-args.c
When the user invokes a.out and passes command-line arguments, the
program echoes those arguments on the terminal. For example:
$ a.out Long Day\’s "Journey into Night"
program: a.out
argument 1: Long
argument 2: Day’s
argument 3: Journey into Night
The shell parses all arguments before passing them to a.out. For this
reason, a single quote must be preceded by a backslash, alphabetic
arguments are delimited by spaces or tabs, and arguments with embedded
spaces or tabs are enclosed in quotation marks.
***ARCHIVE HEADER***
Member Name Date Uid Gid Mode Size
_ _start:
0x120001080: 23defff0 lda sp, -16(sp)
0x120001084: b7fe0008 stq zero, 8(sp)
0x120001088: c0200000 br t0, 0x12000108c
0x12000108c: a21e0010 ldl a0, 16(sp)
0x120001090: 223e0018 lda a1, 24(sp)
.
.
.
In this example, tzset is the weak identifier and _ _tzset is its strong
counterpart. The _ _tzset identifier is the routine that will actually do
the work.
User programs linked as shared should not see such additions to the symbol
table because the weak/strong identifier pairs remain in the shared library.
Existing user programs that reference non-ANSI, nonreserved identifiers
from libc do not need to be recompiled because of these changes, with one
exception: user programs that depended on pre-emption of these identifiers
in libc will no longer be able to pre-empt them using the nonreserved
names. This kind of pre-emption is not ANSI-compliant and is highly
discouraged. However, the ability to pre-empt these identifiers still exists by
using the new reserved names (those preceded by two underscores).
These changes apply to the dynamic and static versions of libc:
• /usr/shlib/libc.so
• /usr/lib/libc.a
main: 4 tzset
(dbx)
...
The source and destination arguments (if any) for
the instruction being generated, and any other
values used in the generated instructions.
These values are made available to the instructions through the normal
argument passing conventions of the calling standard (the first integer
argument is available in register R16).
<macro_sequence> : number
| <register_name>
| "f" number | "F" number
| "r" number | "R" number
;
The following example does not work. There is no value loaded into the
floating-point return register. Furthermore, it results in a compile-time
warning stating that r2 is used before it is set, because the arguments are
loaded into the arg registers and not into r2:
z = fasm("mulq %r2, %a1 %r5", x=10, y=5);
function-assertions
A list of assertions that the compiler uses to make assumptions
about the functions. Specify one or more of the following assertions,
separating multiple assertions with white space:
noreturn
The compiler can assume that any call to the routine will never
return.
nocalls_back
The compiler can assume that no routine in the source module
will be called before control is returned from this function.
nostate
The compiler can assume that only the function’s arguments
determine the value that the function returns and any side-effects
the function might have. If a function is marked as having both
noeffects and nostate, the compiler can eliminate redundant calls
to the function.
file_scope_vars(option)
The compiler can make assumptions about how a function will
access variables that are declared at file scope (with either
internal or external linkage). The option is one of the following
keywords:
none
The function will not read or write to any file-scope variables
except those whose type is volatile or those that are listed
in a #pragma assert global_status_variable.
noreads
The function will not read any file-scope variables except
those whose type is volatile or those that are listed in a
#pragma assert global_status_variable.
nowrites
The function will not write to any file-scope variables except
those whose type is volatile or those that are listed in a
#pragma assert global_status_variable.
first-to-check-index
The number of the first argument to check against the
format string.
This form of the #pragma assert directive must appear at file scope.
The identifiers in the identifier-list must have declarations that are
visible at the point of the #pragma assert directive.
A function can appear on more than one #pragma assert func_attrs
directive as long as each directive specifies a different assertion about the
function. For example, the following is valid:
#pragma assert func_attrs(a) nocalls_back
#pragma assert func_attrs(a) file_scope_vars(noreads)
If the compiler determines that the sizeof a is not 12, it generates the
following message:
cc: Warning: a.c, line 4: The assertion "sizeof(a)==12" was
not true, a is the wrong size. (assertfail)
#pragma extern_prefix
#pragma member_alignment
#pragma message
#pragma pack
#pragma pointer_size
A context pragma can save and restore previous states, usually before and
after including a header file that might also use the same type of pragma.
The #pragma environment directive protects include files from compilation
contexts set by encompassing programs, and protects encompassing
programs from contexts set in header files that they include.
This pragma has the following syntax:
#pragma environment [ cmd_line | hdr_defaults | restore | save ]
cmd_line
Sets the states of all of the context pragmas set on the command line.
You can use this pragma to protect header files from environment
pragmas that take effect before the header file is included.
hdr_defaults
Sets the states of all of the context pragmas to their default values.
This is equivalent to the situation in which a program with no
command-line options and no pragmas is compiled, except that this
pragma sets the pragma message state to #pragma nostandard, as is
appropriate for header files.
restore
Restores the current state of every context pragma.
save
Saves the current state of every context pragma.
Without requiring further changes to the source code, you can use #pragma
environment to protect header files from things such as language
enhancements that might introduce additional compilation contexts.
A header file can selectively inherit the state of a pragma from the including
file and then use additional pragmas as needed to set the compilation to
nondefault states. For example:
In this example:
Therefore, the header file is protected from all pragmas, except for the
member alignment context that the header file was meant to inherit.
strict_refdef
In this model, some declarations are references and some are
definitions. There must be exactly one definition in the program for
any symbol that is referenced. This model is the only one guaranteed
to strictly conform to all ANSI C implementations.
3.3.1 Syntax
The #pragma extern_model directive has the following syntax:
#pragma extern_model model_spec [attr[,attr]...]
model_spec
One of the following:
relaxed_refdef
strict_refdef "name"
[attr[,attr]...]
Optional psect attribute specifications. Choose only one from each of
the following sets of attribute specifications:
shr|noshr
The psect can be shared in memory (shr) or cannot be shared in
memory (noshr). The default is noshr.
wrt|nowrt
The psect contains data that can be modified (wrt) or data that
cannot be modified (nowrt). The default is determined by the
first variable placed in the psect. If the variable has the const
type qualifier (or the readonly modifier), the psect is set to
nowrt. Otherwise, it is set to wrt.
ovr|con
The psect is concatenated with other psects with the same name
(con) or overlaid on the same memory locations (ovr). The default
is con for strict_refdef, and over for relaxed_refdef.
4|octa|5|6|7|8|9|10|11|12|13|14|15|16|page
These denote numeric alignment values. The default alignment is
octa. If a number is specified, the psect is given an alignment of
two raised to the power indicated by that number.
The name in quotes, if specified, is the name of the psect for any definitions.
The default prefix for external identifiers, when none has been specified by a
pragma, is the null string.
The recommended use is as follows:
#pragma extern_prefix save
#pragma extern_prefix " prefix-to-prepend-to-external-names "
...some declarations and definitions ...
#pragma extern_prefix restore
Function Synonym
abs _ _builtin_abs
labs _ _builtin_labs
fabs _ _builtin_fabs
alloca _ _builtin_alloca
strcpy _ _builtin_strcpy
Several methods are available for using intrinsics and built-ins. The
header files containing the declarations of the functions contain the
#pragma intrinsic directive for the functions shown in Table 3–1. To
enable the directive, you must define the preprocessor macro _INTRINSICS.
For alloca, all that is necessary is to include alloca.h.
For example, to get the intrinsic version of abs, a program should
either include stdlib.h and compile with -D_INTRINSICS or define
_INTRINSICS with a #define directive before including stdlib.h.
To enable built-in processing, use the -D switch. For example, to enable the
fabs built-in, the proc.c program is compiled with one of the following:
% cc -Dfabs=_ _builtin_fabs prog.c
% cc -Dabs=_ _builtin_abs prog.c
abs
fabs
labs
alloca
characteristics
Specifies information about where parameters will be passed, where
the results of the function are to be received, and what registers are
modified by the function call.
main()
{
double d;
disable
Disables issuance of the messages specified in the message list. Only
messages of severity Warning or Information can be disabled. If the
message has a severity of Error or Fatal, it is issued regardless of any
attempt to disable it.
emit_once
Emits the specified messages only once per compilation. Certain
messages are emitted only the first time the compiler encounters the
causal condition. When the compiler encounters the same condition
later in the program, no message is emitted. Messages about the use of
language extensions are an example of this kind of message. To emit
one of these messages every time the causal condition is encountered,
use the emit_always option.
Errors and Fatals are always emitted. You cannot set them to
emit_once.
emit_always
Emits the specified messages at every occurrence of the condition.
fatal
Sets the severity of the specified messages to Fatal.
informational
Sets the severity of the specified messages to Informational. Note that
Fatal and Error messages cannot be made less severe.
warning
Sets the severity of each message in the message-list to Warning.
Note that Fatal and Error messages cannot be made less severe.
alignment
Messages about unusual or inefficient data alignment.
c_to_cxx
Messages reporting the use of C features that would be invalid or
have a different meaning if compiled by a C++ compiler.
nonansi
Messages reporting the use of non-ANSI Standard features.
defunct
Messages reporting the use of obsolete features: ones that were
commonly accepted by early C compilers but were subsequently
removed from the language.
obsolescent
Messages reporting the use of features that are valid in ANSI
Standard C, but which were identified in the standard as being
obsolete and likely to be removed from the language in a future
version of the standard.
overflow
Messages that report assignments and/or casts that can cause
overflow or other loss of data significance.
performance
Messages reporting code that might result in poor run-time
performance.
portable
Messages reporting the use of language extensions or other
constructs that might not be portable to other compilers or
platforms.
preprocessor
Messages reporting questionable or nonportable use of
preprocessing constructs.
returnchecks
Messages related to function return values.
uninit
Messages related to using uninitialized variables.
unused
Messages reporting expressions, declarations, header files, static
functions, and code paths that are not used.
level2
Moderately important messages. Level2 is the default for Compaq
C.
level3
Less important messages.
level4
Useful check/portable messages.
level5
Not so useful check/portable messages.
level6
Additional noisy messages.
restore
Restores the previous state of which messages are enabled and
disabled.
The save and restore options are useful primarily within header files.
This form of the pragma is subject to macro replacement. For example, the
following is allowed:
#pragma message ("Compiling file " _ _FILE_ _)
level=n
unroll settings
These control loop unrolling. Specify as follows:
unroll=n
ansi-alias settings
These control ansi-alias assumptions. Specify one of the following:
ansi_alias=on
ansi_alias=off
intrinsic settings
These control recognition of intrinsics. Specify on of the following:
intrinsics=on
intrinsics=off
Example:
#pragma optimize level=5 unroll=6
The save and restore options save and restore the current optimization
state (level, unroll count, ansi-alias setting, and intrinsic setting).
save | restore Saves the current pointer size and restores the saved
pointer size, respectively. The save and restore
options are particularly useful for specifying mixed
pointer support and for protecting header files that
interface to older objects. Objects compiled with
multiple pointer size pragmas will not be compatible
with old objects, and the compiler cannot discern
that incompatible objects are being mixed.
For example:
#pragma pointer_size long
/* pointer sizes in here are 64-bits */
#pragma pointer_size save
#pragma pointer_size short
/* pointer sizes in here are 32-bits */
#pragma pointer_size restore
/* pointer sizes in here are again 64-bits */
The #pragma use_linkage directive must appear in the source file before
any use or definition of the specified routines. Otherwise, the results are
unpredictable.
The following example defines a special linkage and associates it with a
routine that takes three integer parameters and returns a single integer
result in the same location where the first parameter was passed:
#pragma linkage example_linkage (parameters(r16, r17, r19), result(r16))
#pragma use_linkage example_linkage (sub)
int sub (int p1, int p2, short p3);
main()
{
int result;
t *f2;
#include <stdio.h>
main() {
f2 = f1;
b = (*f2)(1);
}
Shared libraries are the default system libraries. The default behavior of
the C compiler is to use shared libraries when performing compile and link
operations.
This chapter addresses the following topics:
• Overview of shared libraries (Section 4.1)
• Resolving symbols (Section 4.2)
• Linking with shared libraries (Section 4.3)
• Turning off shared libraries (Section 4.4)
• Creating shared libraries (Section 4.5)
• Working with private shared libraries (Section 4.6)
• Using quickstart (Section 4.7)
• Debugging programs linked with shared libraries (Section 4.8)
• Loading a shared library at run time (Section 4.9)
• Protecting shared library files (Section 4.10)
• Shared library versioning (Section 4.11)
• Symbol binding (Section 4.12)
• Shared library restrictions (Section 4.13)
process1 process2
scanf.o scanf.o
from libc from libc
kernel
process1 process2
information information
to load libc to load libc
libc
kernel
ZK-0474U-AI
1. /usr/shlib
2. /usr/ccs/lib
3. /usr/lib/cmplrs/cc
4. /usr/lib
5. /usr/local/lib
6. /var/shlib
If the linker does not find a shared library, it searches through the same
directories again, looking for an archive (.a) library. You can prevent the
search for archive libraries by using the −no_archive option on the ld
command.
If the loader cannot find the library it needs in the paths defined by any of
the preceding steps, it looks through the directories specified in the default
path described in Section 4.2.1. In addition, you can use the _RLD_ROOT
environment variable to alter the search path of the run-time loader. For
more information, see loader(5).
Note that because symbol resolution always prefers the main object, shared
libraries can be set up to call back into a defined symbol in the main object.
Likewise, the main object can define a symbol that will override (preempt or
hook) a definition in a shared library.
-warning_unresolved
This option specifies that all unresolved symbols except those matching
the −expect_unresolved pattern produce warning messages. This
mode is the default for linking shared libraries.
-error_unresolved
This option causes the linker to print an error message and return a
nonzero error status when a link is completed with unresolved symbols
To exclude the default directories from the search and limit the search to
specific directories and specific libraries, specify the -L option first with no
arguments. Then, specify it again with the directory to search, followed
by the -l option with the name of the library to search for. For example,
to limit the search path to /usr/person for use with the private library
libmylib.so, enter the following command:
% cc -o hello hello.c -L -L/usr/person -lmylib
Note that because the cc command always implicitly links in the C library,
the preceding example requires that a copy of libc.so or libc.a must
be in the /usr/person directory.
The -no_archive option tells the linker to resolve symbols using only
shared libraries. The -lc option tells the linker to look in the system C
shared library for unresolved symbols.
To make a shared library available on a system level by copying it into
the /usr/shlib directory, you must have root privileges. System shared
libraries should be located in the /usr/shlib directory or in one of the
default directories so that the run-time loader (/sbin/loader) can locate
them without requiring every user to set the LD_LIBRARY_PATH variable to
directories other than those in the default path.
In this example, the -all option tells the linker to link all the objects from
the archive library old.a. The -none option tells the linker to turn off the
-all option. Note that the -no_archive option applies to the resolution of
the -lc option but not to old.a (because old.a is explicitly mentioned).
% cc -c admin.c
% cc -o admin admin.o -L. -lcommon
4. Copy libcommon.so into a directory pointed to by LD_LIBRARY_PATH,
if it is not already in that directory.
5. Run each compiled program (user, db, and admin).
You can now build your libraries. If your library builds occur in multiple
directories, use the -update_registry option to the ld command to
explicitly specify the location of a common so_locations file. For example:
If you install your shared libraries globally for all users of your system,
update the systemwide so_locations file. Enter the following commands
as root, with shared_library.so being the name of your actual shared
library:
# cp shared_library.so /usr/shlib
# mv /usr/shlib/so_locations /usr/shlib/so_locations.old
# cp so_locations /usr/shlib
The next example (used1.c) defines symbols and demonstrates how to use
the dlopen function:
#include <stdio.h>
#include <dlfcn.h>
The following example shows the makefile that makes pr.o, pr.so,
so_locations, and usedl.o:
# this is the makefile to test the examples
all: runit
usedl: usedl.c
$(CC) -o usedl usedl.c
pr.so: pr.o
In addition, segment sharing can occur with any file that uses the mmap
system call without the PROT_WRITE flag as long as the mapped address
falls in the same memory segment as other files using mmap.
Any program using mmap to examine files that might be highly protected can
ensure that no segment sharing takes place by introducing a writable page
into the segment before or during the mmap. The easiest way to provide
protection is to use the mmap system call on the file with PROT_WRITE
enabled in the protection, and use the mprotect system call to make the
mapped memory read-only. Alternatively, to disable all segmentation and to
avoid any unauthorized sharing, enter the following line in the configuration
file:
segmentation 0
You can use the odump command to examine a shared library’s versions
string, as set by using the -set_version version-string option of the
ld command that created the library. For example:
% odump -D library-name
The value displayed for the IVERSION field is the version string specified
when the library was built. If a shared library is built without the
-set_version option, no IVERSION field will be displayed. These shared
libraries are handled as if they had been built with the version identifier
_null.
When ld links a shared object, it records the version of each shared library
dependency. Only the rightmost version identifier in a colon-separated list is
a.out
libA.so libB.so
libcommon.so
ZK-0882U-AI
appl_1
layrd1.so layrd2.so
libc.so(osf.1) libc.so(osf.2)
ZK-0884U-AI
In Figure 4–4, an application is linked with a layered product that was built
with an incompatible version of the base system.
appl_2
layrd1.so libc.so(osf.2)
libc.so(osf.1)
ZK-0885U-AI
appl_3
libc_r.so(osf.2) libc.so(osf.1)
libc.so(osf.2)
ZK-0886U-AI
The following figures show valid uses of multiple versions of shared libraries.
In Figure 4–6, an application uses a backward-compatibility library
implemented as a partial shared library.
appl_4
libc.so(osf.1)
libc.so(osf.2)
libc.so(osf.3)
ZK-0887U-AI
appl_5
libc_r.so(osf.1) libc.so(osf.1)
libc_r.so(osf.2) libc.so(osf.2)
ZK-0888U-AI
The following example shows the use of the uppercase words in commands:
(dbx) stop VAR in PROCEDURE if EXP
Enter stop, in, and if as shown. Enter the values for VAR, PROCEDURE,
and EXP as defined in Table 5–1.
1 The most recently called procedure is prnt. The activation level of prnt
is 0; this function is at the top of the stack.
2 The main program is main.
3 Activation level number. The angle bracket ( >) indicates the activation
level that is currently under examination.
1. Invoke the program under dbx, specifying any appropriate options and
the names of the executable file and the core dump file on the dbx
command line.
2. Get a stack trace using the where command to locate the point of failure.
3. Set breakpoints to isolate the error using the stop or stopi commands.
4. Display the values of variables using the print command to see where
a variable might have been assigned an incorrect value.
If you still cannot find the error, other dbx commands described in this
chapter might be useful.
Use the quit or q command to end a debugging session. The quit command
accepts no arguments.
1 Current file
2 Procedure name
3 Variable name
Operators follow the C language precedence. Table 5–4 shows the language
operators recognized by dbx in order of precedence from top to bottom and
from left to right, with the dbx-specific number-sign operator included
among the unary operators to show its place in the precedence hierarchy.
You can use the built-in data types for type coercion — for example, to
display the value of a variable in a type other than the type specified in the
variable’s declaration. The dbx debugger understands C language data
types, so that you can refer to data types without the dollar sign ($). The
types of constants that are acceptable as input to dbx are shown in Table 5–6.
Constants are displayed by default as decimal values in dbx output.
Notes:
• Overflow on nonfloat uses the rightmost digits. Overflow on float uses
the leftmost digits of the mantissa and the highest or lowest exponent
possible.
• The $octin variable changes the default input expected to octal. The
$hexin variable changes the default input expected to hexadecimal
(see Section 5.5.2).
• The $octints variable changes the default output to octal. The
$hexints variable changes the default output to hexadecimal (see
Section 5.5.2).
Return key Repeats the last command that you entered. You can
disable this feature by setting the $repeatmode
variable to 0 (see Section 5.5.1).
The following example displays the history list and then repeats execution
of the twelfth command in the list:
(dbx) history
10 print x
11 print y
12 print z
(dbx) !12
(!12 = print z)
123
(dbx)
The following example shows symbol name completion. In this case, the
entry supplied is unambiguous:
(dbx) print file Ctrl/Z
(dbx) print file_header_ptr
0x124ac
(dbx)
The following example shows the use of the set and unset commands:
(dbx) set 1
$listwindow 10
$datacache 1
$main "main"
$pagewindow 22
test 5
$page 1
$maxstrlen 128
$cursrcline 24
more (n if no)? n
(dbx) set test = 12 2
(dbx) set
$listwindow 10
$datacache 1
$main "main"
$pagewindow 22
test 12
$page 1
$maxstrlen 128
$cursrcline 24
more (n if no)? n
(dbx) unset test 3
(dbx) set
$listwindow 10
$datacache 1
$main "main"
$pagewindow 22
$page 1
$maxstrlen 128
$cursrcline 24
more (n if no)? n
(dbx)
unalias NAME
Removes an alias from a command, where NAME is the alias name.
The following example shows the use of the alias and unalias commands:
(dbx) alias 1
h history
si stepi
Si nexti
.
.
.
g goto
s step
More (n if no) ?n
(dbx) alias ok(x) "stop at x" 2
(dbx) ok(52) 3
[2] Stop at "sam.c":52 4
(dbx)
(dbx) unalias h 5
(dbx) alias
si stepi
Si nexti
.
.
.
g goto
s step
More (n if no)? n
(dbx)
1 Display aliases.
2 Define an alias for setting a breakpoint.
3 Set a breakpoint at line 52.
4 Debugger acknowledges breakpoint set at line 52.
5 Remove the h alias. (Note that it disappears from the alias list.)
The numbers in brackets (for example, [2]) indicate status item numbers.
delete all
delete *
Deletes all status items.
disable all
enable all
Disables or enables all events.
• During the dbx session, if you want to load a shared library dynamically,
first set the $module_path dbx variable and then use the addobj
command to load the library, as in the following example:
(dbx) set $module_path /usr/project4/lib_dir
(dbx) addobj libdef.so
To verify that modules are being loaded from the correct location, turn on
verbose module-loading using any one of the following methods:
• Specify the -module_verbose dbx command option.
For example:
1 Current directory
2 New directory
The where command displays a stack trace showing the current activation
levels (active procedures) of the program being debugged. The tstack
command displays a stack trace for all threads. See Section 5.12 for more
information about debugging threads.
The where and tstack commands have the following form:
where [EXP]
tstack [EXP] Displays a stack trace.
If EXP is specified, dbx displays only the top EXP levels of the stack;
otherwise, the entire stack is displayed.
If a breakpoint is set in prnt in the sample program sam.c, the program
runs and stops in the procedure prnt(). If you enter where, the debugger’s
stack trace provides the information shown in the following example:
(dbx) stop in prnt
[1] stop in prnt
.
(dbx) run.
.
(dbx) where 1
> 0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04]
| | | | | |
1 2 3 4 5 6
(dbx)
1 Activation level
2 Procedure name
The up and down commands move you directly up or down in the stack; they
are useful when tracking a call from one level to another.
The func command can move you up or down incrementally or to a specific
activation level or procedure. The func command changes the current line,
the current file, and the current procedure, which changes the scope of the
variables you can access. You can also use the func command to examine
source code when a program is not executing.
The up, down, and func commands have the following forms:
up [EXP] Moves up the specified number of activation levels in
the stack. The default is one level.
For example:
(dbx) file
sam.c 1
(dbx) file data.c
(dbx) file
data.c 2
(dbx)
1 Current file
2 New file
list EXP:INT Starting at the specified line (EXP), lists the specified
number of lines (INT), overriding $listwindow.
If you use the list command’s predefined alias w, the output is as follows:
(dbx) w
45 prnt(&line1);
46 }
47 }
48
49 void prnt(pline)
> 50 LINETYPE *pline;
51 {
* 52 fprintf(stdout,"%3d. (%3d) %s",pline->linenumber,
53 pline->length, pline->string);
54 fflush(stdout);
The right angle bracket in column 1 ( >) indicates the current line, and the
asterisk in column 2 ( *) indicates the location of the program counter (PC)
at this activation level.
For example:
(dbx) /lines
no match
(dbx) /line1
16 LINETYPE line1;
(dbx) /
39 while(fgets(line1.string, sizeof(line1.string), fd) != NULL){
(dbx)
The edit command loads the editor indicated by the environment variable
EDITOR or, if EDITOR is not set, the vi editor. To return to dbx, exit normally
from the editor.
For example:
(dbx) whatis main
int main(argc,argv)
int argc;
unsigned char **argv;
(dbx) whatis i
int i;
(dbx)
The run, args, and rerun commands have the following forms:
run [ARG1 ... ARGN] [<FILE1] [>FILE2]
run [ARG1 ... ARGN] [<FILE1] [>&FILE2]
Runs the program with the specified arguments and redirections.
For example:
(dbx) run sam.c 1
0. (19)#include <stdio.h>
1. (14) struct line {
2. (19) char string[256];
.
.
.
next [EXP]
nexti [EXP] Executes the specified number of source-code lines or
machine instructions in only the current procedure,
regardless of the number of lines executed in any
called procedures. The default is 1.
For example:
(dbx) rerun
[7] stopped at [prnt:52,0x120000c04] fprintf(stdout,"%3d.(%3d) %s",
(dbx) step 2
return PROCEDURE Executes the rest of the current procedure and any
calling procedures intervening between the current
procedure and the procedure named by PROCEDURE.
Stops at the point of the call in the procedure that
is named.
For example:
(dbx) rerun
[7] stopped at [prnt:52,0x120000c04] fprintf(stdout,"%3d.(%3d) %s",
(dbx) return
0. (19) #include <stdio.h>
stopped at [main:45 +0xc,0x120000bb0] prnt(&line1);
(dbx)
For example:
(dbx) when at 40 {goto 43}
[8] start sam.c:43 at "sam.c":40
(dbx)
cont to LINE
conti to ADDRESS
Continues until the specified source-code line or machine-code address.
cont in PROCEDURE
conti in PROCEDURE
Continues until the specified procedure.
cont SIGNAL
conti SIGNAL
After receiving the specified signal, continues from the current line or
machine instruction.
The following example shows the use of the cont command in a C program:
(dbx) stop in prnt
[9] stop in prnt
(dbx) rerun
[9] stopped at [prnt:52,0x120000c04] fprintf(stdout,"%3d.(%3d) %s",
(dbx) cont
0. ( 19) #include <stdio.h>
[9] stopped at [prnt:52,0x120000c04] fprintf(stdout,"%3d.(%3d) %s",
(dbx)
For example:
(dbx) print i
19 1
(dbx) assign i = 10
10 2
(dbx) assign *(int *)0x444 = 1 3
1
(dbx)
1 The value of i.
2 The new value of i.
3 Coerce the address to be an integer and assign a value of 1 to it.
The patch is applied to the default disk file; you can use qualified variable
names to specify a patch to a file other than the default. Applying a patch in
this way also patches the in-memory image of the file being patched.
For example:
(dbx) stop in prnt 1
[11] stop in prnt
(dbx) call prnt(&line1) 2
[11] stopped at [prnt:52,0x120000c] fprintf(stdout,"%3d.(%3d) %s",
(dbx) status 3
[11] stop in prnt
[12] stop at "sam.c":40
[2] record output example2 (126 lines)
(dbx) delete 11,12 4
(dbx)
For example:
(dbx) setenv TEXT "sam.c" 1
(dbx) run 2
[4] stopped at [prnt:52,0x120000e34] fprintf(stdout,"%3d.(%3d) %s",
(dbx) setenv TEXT "" 3
(dbx) run 4
Usage: sam filename
1 The setenv command sets the environment variable TEXT to the value
sam.c.
2 The run command executes the program from the beginning. The
program reads input from the file named in the the environment
variable TEXT. Program execution stops at the breakpoint at line 52.
3 The setenv command sets the environment variable TEXT to null.
4 The run command executes the program. Because the TEXT
environment variable contains a null value, the program must get input.
stop if EXP
stopi if EXP
Stops if EXP is true.
stop in PROCEDURE
stopi in PROCEDURE
Stops at the beginning of the procedure.
For example:
(dbx) trace i
[5] trace i in main
(dbx) rerun sam.c
[4] [main:25 ,0x400a50]
(dbx) c
[5] i changed before [main: line 41]:
new value = 19;
[5] i changed before [main: line 41]:
old value = 19;
new value = 14;
[5] i changed before [main: line 41]:
old value = 14;
new value = 19;
[5] i changed before [main: line 41]:
old value = 19;
new value = 13;
[5] i changed before [main: line 41]:
old value = 13;
new value = 17;
For example:
(dbx) when in prnt {print line1.length}
[6] print line1.length in prnt
(dbx) rerun
19 1
14
19
.
.
.
17
59
45
12
More (n if no)?
(dbx) delete 6
(dbx) when in prnt {stop}
[7] stop in prnt
(dbx) rerun
1 Value of line1.length.
2 Stops in the procedure prnt.
ignore Displays a list of all signals that dbx does not catch.
ignore SIGNAL Removes a signal from the catch list and adds it
to the ignore list.
For example:
(dbx) catch 1
INT QUIT ILL TRAP ABRT EMT FPE BUS SEGV SYS PIPE TERM URG \
STOP TTIN TTOU IO XCPU XFSZ VTALRM PROF WINCH INFO USR1 USR2
(dbx) ignore 2
HUP KILL ALRM TSTP CONT CHLD
(dbx) catch kill 3
(dbx) catch
INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE TERM URG \
STOP TTIN TTOU IO XCPU XFSZ VTALRM PROF WINCH INFO USR1 USR2
(dbx) ignore
HUP ALRM TSTP CONT CHLD
(dbx)
You can also specify prefixed registers in the print command to display a
register value or the program counter. The following commands display the
values of machine register 3 and the program counter:
(dbx) print $r3
(dbx) print $pc
For example:
(dbx) print i
14 1
(dbx) po i
016 2
(dbx) px i
0xe 3
(dbx) pd i
14 4
(dbx)
1 Decimal
2 Octal
3 Hexadecimal
4 Decimal
For example:
(dbx) where
> 0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04]
1 main(argc = 2, argv = 0x11ffffe08) ["sam.c":45, 0x120000bac]
(dbx) dump
prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04]
(dbx) dump .
> 0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04]
The following example shows the output when displaying memory addresses
as instructions:
The record input command records debugger input. The playback input
command repeats a recorded sequence. The record input and
playback input commands have the following forms:
record input [FILE]
Begins recording dbx commands in the specified file or, if no file is
specified, in a file placed in /tmp and given a generated name.
The name given to the temporary file, if used, is contained in the debugger
variable $defaultin. To display the temporary file name, use the print
command:
(dbx) print $defaultin
Use a temporary file when you need to refer to the saved output only during
the current debugging session; specify a file name to save information
for reuse after you end the current debugging session. Use the status
command to see whether recording is active. Use the delete command to
stop recording. Note that these commands will appear in the recording; if
you are creating a file for future use, you will probably want to edit the file
to remove commands of this type.
Use the playback input command to replay the commands recorded with
the record input command. By default, playback is silent; you do not see
the commands as they are played. If the dbx variable $pimode is set to 1,
dbx displays commands as they are played back.
The following example records input and displays the resulting file:
(dbx) record input 1
[2] record input /tmp/dbxtX026963 (0 lines)
(dbx) status
[2] record input /tmp/dbxtX026963 (1 lines)
(dbx) stop in prnt
[3] stop in prnt
(dbx) when i = 19 {stop}
[4] stop ifchanged i = 19
(dbx) delete 2 2
(dbx) playback input 3
[3] stop in prnt
[4] stop ifchanged i = 19
[5] stop in prnt
[6] stop ifchanged i = 19
/tmp/dbxtX026963: 4: unknown event 2 4
(dbx)
1 Start recording.
2 Stop recording.
3 Play back the recorded input. As events 3 and 4 are played, they create
duplicates of themselves, numbered 5 and 6, respectively.
The temporary file resulting from the preceding dbx commands contains
the following text:
status
stop in prnt
when i = 19 {stop}
delete 2
Use the record output command to record dbx output during a debugging
session. To produce a complete record of activity by recording input along
with the output, set the dbx variable $rimode. You can use the debugger’s
playback output command to look at the recorded information, or you
can use any text editor.
The record output and playback output commands have the following
forms:
record output [FILE]
Begins recording dbx output in the specified file or, if no file is specified,
in a file placed in /tmp and given a generated name.
The name given to the temporary file, if used, is contained in the debugger
variable $defaultout. To display the temporary file name, use the print
command:
(dbx) print $defaultout
The playback output command works the same as the cat command; a
display from the record output command is identical to the contents of
the recording file.
Use a temporary file when you need to refer to the saved output only during
the current debugging session; specify a file name to save information
for reuse after you end the current debugging session. Use the status
command to see whether recording is active. Use the delete command
to stop recording.
The following example shows a sample dbx interaction and the output
recorded for this interaction in a file named code:
When you enable core-file naming, the system produces core files with
names in the following format:
core.prog-name.host-name.tag
The name of the core file has four parts separated by periods:
• The literal string core.
• Up to 16 characters of the program name, as displayed by the ps
command.
• Up to 16 characters of the system’s network host name, as derived from
the part of the host name that precedes the first dot in the host name
format.
• A numeric tag that is assigned to the core file to make it unique among
all of the core files generated by a program on a host. The maximum
value for this tag, and therefore the maximum number of core files for
this program and host, is set by a system configuration parameter (see
Section 5.10.1).
The tag is not a literal version number. The system selects the first
available unique tag for the core file. For example, if a program’s core
files have tags 0, 1, and 3, the system uses tag 2 for the next core file it
creates for that program. If the system-configured limit for core-file
instances is reached, no further core files are created for that program
and host combination. By default, up to 16 versions of a core file can
be created.
To conserve disk space, be sure to remove core files after you have
examined them. This is necessary because named core files are not
overwritten.
enhanced-core-name = 1
enhanced-core-max-versions = 8
You can also attach to a process for debugging by using the command-line
option −pid process id.
To detach from a running process, use the dbx command detach, which
has the following form:
detach [process-id ]
The optional process-id argument is the process ID of the process
you want to detach from. If no argument is given, dbx detaches from
the current process.
To change from one process to another, use the dbx command switch, which
has the following form:
switch process-id
The process-id argument is the process ID of the process you want
to switch to. You must already have attached to a process before you
can switch to it. You can use the alias sw for the switch command.
The attach command first checks to see whether /proc is mounted; dbx
gives a warning that tells you what to do if it is not mounted. If /proc
is mounted, dbx looks for the process ID in /proc. If the process ID is in
/proc, dbx attempts to open the process and issues a stop command. If
the process is not there or if the permissions do not allow attaching to it,
dbx reports this failure.
When the stop command takes effect, dbx reports the current position,
issues a prompt, and waits for user commands. The program probably will
not be stopped directly in the user code; it will more likely be stopped in a
library or system call that was called by user code.
If the POSIX Threads Library product is installed on your system, you can
gain access to the POSIX Threads Library pthread debugger by issuing
(dbx) tlist
(dbx) quit
#include <stdio.h>
struct line {
char string[256];
int length;
int linenumber;
};
void prnt();
main(argc,argv)
int argc;
char **argv;
{
LINETYPE line1;
FILE *fd;
extern FILE *fopen();
if (argc < 2) {
if((fname = getenv("TEXT")) == NULL || *fname == ’ ’) {
fprintf(stderr, "Usage: sam filename\n");
exit(1);
}
} else
fname = argv[1];
fd = fopen(fname,"r");
if (fd == NULL) {
fprintf(stderr, "cannot open %s\n",fname);
exit(1);
}
void prnt(pline)
LINETYPE *pline;
{
fprintf(stdout,"%3d. (%3d) %s",
pline->linenumber, pline->length, pline->string);
fflush(stdout);
}
You can use the lint program to check your C programs for potential coding
problems. The lint program checks a program more carefully than some C
compilers, and displays messages that point out possible problems. Some
of the messages require corrections to the source code; others are only
informational messages and do not require corrections.
This chapter addresses the following topics:
• Syntax of the lint command (Section 6.1)
• Program flow checking (Section 6.2)
• Data type checking (Section 6.3)
• Variable and function checking (Section 6.4)
• Checking the use of variables before they are initialized (Section 6.5)
• Migration checking (Section 6.6)
• Portability checking (Section 6.7)
• Checking for coding errors and coding style differences (Section 6.8)
• Increasing table sizes for large programs (Section 6.9)
• Creating a lint library (Section 6.10)
• Understanding lint error messages (Section 6.11)
• Using warning class options to suppress lint messages (Section 6.12)
• Generating function prototypes for compile-time detection of syntax
errors (Section 6.13)
See lint(1) for a complete list of lint options.
file
The name of the C language source file for lint to check. The name
must have one of the following suffixes:
Suffix Description
.c C source file
.i File produced by the C preprocessor (cpp)
.ln lint library file
Note that lint library files are the result of a previous invocation
of the lint program with either the -c or -o option. They are
analogous to the .o files produced by the cc command when it is
given a .c file as input. The ability to specify lint libraries as input
to the lint program facilitates intermodule interface checking in
large applications. Adding rules that specify the construction of lint
libraries to their makefiles can make building such applications more
efficient. See Section 6.10 for a discussion on how to create a lint
library.
You can also specify as input a lint library that resides in one of the
system’s default library search directories by using the -lx option. The
library name must have the following form:
If you specify no options on the command line, the lint program checks
the specified C source files and writes messages about any of the following
coding problems that it finds:
• Loops that are not entered and exited normally
• Data types that are not used correctly
• Functions that are not used correctly
• Variables that are not used correctly
• Coding techniques that could cause problems if a program is moved to
another system
• Nonstandard coding practices and style differences that could cause
problems
The lint program also checks for syntax errors in statements in the source
programs. Syntax checking is always done and is not influenced by any
options that you specify on the lint command.
If lint does not report any errors, the program has correct syntax and will
compile without errors. Passing that test, however, does not mean that
the program will operate correctly or that the logic design of the program
is accurate.
See Section 6.10 for information on how to create your own lint library.
char
short
int
long
unsigned
float
double
The data types of pointers must agree exactly, except that you can mix
arrays of any type with pointers to the same type.
char
short
int
unsigned
6.3.4 Enumerators
The lint program checks enumerated data type variables to ensure that
they meet the following requirements:
• Enumerator variables or members of an enumerated type are not mixed
with other types or other enumerator variables.
• The enumerated data type variables are only used in the following areas:
Assignment (=)
Initialization
Equivalence (==)
Not equivalence (!=)
Function arguments
Return values
return;
These statements cause the lint program to write the following message
to point out the potential problem:
function name has return(e); and return
The lint program also checks functions for returns that are caused by
reaching the end of the function code (an implied return). For example, in
the following part of a function, if a tests false, checkout calls fix_it and
then returns with no defined return value:
checkout (a)
{
if (a) return (3);
fix_it ();
}
These statements cause the lint program to write the following message:
function checkout has return(e); and return
If fix_it, like exit, never returns, lint still writes the message even
though nothing is wrong.
#include <dms.h>
The input file is a text file that you create with an editor. It consists of:
• A directive to tell the cpp program that the following information is to be
made into a library of lint definitions:
/*LINTLIBRARY*/
• A series of function definitions that define:
In the case where a header file may include other headers, the LINTSTDLIB
command can be restricted to specific files:
/*LINTSTDLIB_dms.h*/
This command tells lint to create a lint library file, llib-ldms.ln, using
the file llib-ldms.c as input. To use llib-ldms.ln as a system lint
library (that is, a library specified in the -lx option of the lint command),
move it to /usr/ccs/lib. Use the −std or −std1 option to use ANSI
preprocessing rules to build the library.
main()
{
int value = !SUCCESS;
#define QWAIT 1
#define QNOWAIT 0
#define DEQUEUE(q, elt, wait) 1 \
for (;;) {
simple_lock(&(q)->lock);
if (queue_empty(&(q)->head))
if (wait) { 1 \
assert(q);
simple_unlock(&(q)->lock);
continue;
} else
*(elt) = 0;
else
dequeue_head(&(q)->head);
simple_unlock(&(q)->lock);
break;
}
1 The lint program reports the conversion error, even though the
appropriate (int) cast exists.
main()
{
if (offset < 0) { 1
puts ("code is Ok...");
return 0;
} else {
puts ("unsigned comparison failed...");
return 1;
}
}
% cc -g -o x x.c
% lint x.c
"x.c" line 7: warning: degenerate unsigned comparison
% ./x
unsigned comparison failed...
null effect
The lint program detected a cast or statement that does nothing. The
following code segments demonstrate various coding practices that
cause lint to generate this message:
scsi_slot = device->ctlr_hd->slot,unit_str; 1
#define MCLUNREF(p) \
(MCLMAPPED(p) && --mclrefcnt[mtocl(p)] == 0)
(void) MCLUNREF(m); 2
void
test()
{
bt.block_len = 0xff;
}
% lint -u x.c
"x.c", line 8: warning: precision lost in field assignment
% cc -c -o x x.c
%
This code compiles without error. However, because the bit field may
be too small to hold the constant, the results may not be what the
programmer intended and a run-time error may occur.
Recommended Action: Change the bit field size or assign a different
constant value.
Recommended Action: You can fix the previous example in two ways:
• Add an (int) cast before offset in the if comparison.
• Change the declaration of offset from unsigned to int.
The Third Degree tool checks for leaking heap memory, referencing invalid
addresses and reading uninitialized memory in C and C++ programs.
Programs must first be compiled with either the -g or -gn option, where
n is greater than 0. Third Degree also helps you determine the allocation
habits of your program by listing heap objects and finding wasted memory.
It accomplishes this by instrumenting executable objects with extra code
that automatically monitors memory management services and load/store
instructions at run time. The requested reports are written to one or more
log files that can optionally be displayed, or associated with source code by
using the xemacs(1) editor.
By default, Third Degree checks only for memory leaks, resulting in fast
instrumentation and run-time analysis. The other more expensive and
intrusive checks are selected with options on the command line. See
third(1) for more information.
You can use Third Degree for the following types of applications:
• Applications that allocate memory by using the malloc, calloc,
realloc, valloc, alloca, and sbrk functions and the C++ new
function. You can also use Third Degree to instrument programs using
other memory allocators, such as the mmap function, but it will not check
accesses to the memory obtained in this manner. If your application uses
mmap, see the description of the -mapbase option in third(1).
Third Degree detects and forbids calls to the brk function. Furthermore,
if your program allocates memory by partitioning large blocks that it
obtained by using the sbrk function, Third Degree may not be able to
precisely identify memory blocks in which errors occur.
• Applications that call fork(2). You must specify the -fork option with
the third(1) command.
• Applications that use the Tru64 UNIX implementation of POSIX
threads (pthread(3)). You must specify the -pthread option with the
third(1) command. In pthread programs, Third Degree does not check
system-library routines (for example, libc and libpthread) for access
to invalid addresses or uninitialized variables; therefore, strcpy and
other such routines will not be checked.
• Applications that use 31–bit heap addresses.
−dirname directory-name
Specifies the directory path in which Third Degree creates its log file.
-fork
Includes the PID in the name of the log file for each forked process.
Depending on the option supplied, the log file’s name will be as follows:
−excobj objname
Excludes the named shared library from instrumentation. You can use
the −excobj option more than once to specify several shared libraries.
−incobj objname
Instruments the named shared library. You can use the −incobj
option more than once to specify several shared libraries, including
those loaded using dlopen().
The following sections explain how to use Third Degree to debug this sample
application.
The types of errors that Third Degree can detect at run-time include such
conditions as reading uninitialized memory, reading or writing unallocated
memory, freeing invalid memory, and certain serious errors likely to cause
an exception. For each error, an error entry is generated with the following
items:
• A banner line with the type of error and number — The error banner
line contains a three-letter abbreviation of each error (see Section 7.3
for a list of the abbreviations). If the process that caused the error is
not the root process (for instance, because the application forks one or
more child processes), the PID of the process that caused the error also
appears in the banner line.
• An error message line formatted to look like a compiler error message —
Third Degree lists the file name and line number nearest to the location
where the error occurred. Usually this is the precise location where the
error occurred, but if the error occurs in a library routine, it can also
point to the place where the library call occurred.
• One or more stack traces — The last part of an error entry is a stack
trace. The first procedure listed in the stack trace is the procedure in
which the error occurred.
The following examples show entries from the log file:
• The following log entry indicates that a local variable of procedure
GetValue was read before being initialized. The line number confirms
that q was never given a value.
---------------------------------------------------- rus -- 0 --
ex.c: 6: reading uninitialized local variable q of GetValue
GetValue ex, ex.c, line 6
GetArray ex, ex.c, line 11
main ex, ex.c, line 20
__start ex
• The following log entry indicates that the program has written to the
memory location one position past the end of the array, potentially
overwriting important data or even Third Degree internal data
structures. Keep in mind that certain errors reported later could be a
consequence of this error:
---------------------------------------------------- wih -- 2 --
ex.c: 14: writing invalid heap 1 byte beyond 160-byte block
GetArray ex, ex.c, line 14
main ex, ex.c, line 20
__start ex
• The following log entry indicates that an error occurred while freeing
memory that was previously freed. For errors involving calls to the free
function, Third Degree usually gives three call stacks:
– The call stack where the error occurred
– The call stack where the object was allocated
– The call stack where the object was freed
Upon examining the program, it is clear that the second call to GetArray
(line 20) frees the object (line 14), and that another attempt to free the
same object occurs at line 21:
---------------------------------------------------- fof -- 3 --
ex.c: 22: freeing already freed heap at byte 0 of 32-byte block
free ex
main ex, ex.c, line 22
__start ex
The following excerpt shows the report generated when leak detection on
program exit, the default, is selected. The report shows a list of memory
leaks sorted by importance and by call stack.
------------------------------------------------------------------------
------------------------------------------------------------------------
New blocks in heap after program exit
160 bytes in 1 leak (including 1 not referenced by other leaks) created at:
malloc ex
GetArray ex, ex.c, line 10
main ex, ex.c, line 20
__start ex
Upon examining the source, it is clear that the first call to GetArray did
not free the memory block, nor was it freed anywhere else in the program.
Moreover, no pointer to this block exists in any other heap block, so it
qualifies as “not referenced by other leaks”. The distinction is often
useful to find the real culprit for large memory leaks.
Consider a large tree structure and assume that the pointer to the root has
been erased. Every block in the structure is a leak, but losing the pointer
to the root is the real cause of the leak. Because all blocks but the root still
have pointers to them, albeit only from other leaks, only the root will be
specially qualified, and therefore the likely cause of the memory loss.
------------------------------------------------------------------
160 bytes allocated (8% written) in 1 objects created at:
malloc ex
GetArray ex, ex.c, line 10
main ex, ex.c, line 20
__start ex
Contents:
0: i.ii....................................
------------------------------------------------------------------
32 bytes allocated (38% written) in 1 objects created at:
malloc ex
GetArray ex, ex.c, line 10
main ex, ex.c, line 21
__start ex
Contents:
0: i.ii....
The sample program allocated two objects for a total of 192 bytes (8*(20+4)).
Because each object was allocated from a different call stack, there are two
entries in the history. Only the first few bytes of each array were set to a
valid value, resulting in the written ratios shown.
If the sample program was a real application, the fact that so little of the
dynamic memory was ever initialized is a warning that it was probably
using memory ineffectively.
See Section 7.4.4 for more information.
The memory layout section of the report summarizes the memory used by
the program by size and address range. The following excerpt shows a
memory layout section:
-----------------------------------------------------------------
-----------------------------------------------------------------
memory layout at program exit
heap 40960 bytes [0x14000c000-0x140016000]
stack 2720 bytes [0x11ffff560-0x120000000]
ex data 48528 bytes [0x140000000-0x14000bd90]
ex text 1179648 bytes [0x120000000-0x120110000]
The heap size and address range indicated reflect the value returned by
sbrk(0), (the heap break) at program exit. Therefore, the size is the total
amount of heap space that has been allotted to the process. Third Degree
does not support the use of the malloc variables that would alter this
interpretation of sbrk(0).
The stack size and address range reflect the lowest address reached by the
main thread’s stack pointer during execution of the program. That is, Third
Degree keeps track of it through each instrumented procedure call. For this
value to reflect the maximum stack size, all shared libraries need to have
been instrumented (for example, using the third(1) command’s -all option
for a nonthreaded program and -incobj options for libraries loaded with
dlopen(3)). The stacks of threads (created using pthread_create) are
not included.
The data and text sizes and address ranges show where the static portions of
the executable and each shared library were loaded.
Name Error
ror Reading out of range: not heap, stack, or static
(for example, NULL)
ris Reading invalid data in stack: probably an array bound error
rus Reading an uninitialized (but valid) location in stack
rih Reading invalid data in heap: probably an array bound error
ruh Reading an uninitialized (but valid) location in heap
wor Writing out of range: neither in heap, stack, or static area
wis Writing invalid data in stack: probably an array bound error
wih Writing invalid data in heap: probably an array bound error
for Freeing out of range: neither in heap or stack
fis Freeing an address in the stack
fih Freeing an invalid address in the heap: no valid object there
fof Freeing an already freed object
fon Freeing a null pointer (really just a warning)
mrn malloc returned null
You can suppress the reporting of specific memory errors by specifying one
or more -ignore options. This is often useful when the errors occur within
library functions for which you do not have the source. Third Degree allows
you to suppress specific memory errors in individual procedures and files,
and at particular line numbers. See third(1) for more details.
Alternatively, do not select the library for checking, by specifying -excobj
or omitting the -all or -incobj option.
Third Degree tries to point as closely as possible to the source of the error,
and it usually gives the file and line number of a procedure near the top
of the call stack when the error occurred, as in this example. However,
Third Degree may not be able to find this source file, either because it is in
a library or because it is not in the current directory. In this case, Third
Degree moves down the call stack until it finds a source file to which it can
point. Usually, this is the point of call of the library routine.
To tag these error messages, Third Degree must determine the location of
the program’s source files. If you are running Third Degree in the directory
containing the source files, Third Degree will locate the source files there.
If not, to add directories to Third Degree’s search path, specify one or more
-use options. This allows Third Degree to find the source files contained
in other directories. The location of each source file is the first directory on
the search path in which it is found.
When you instrument this program, providing the same (or no) options,
Third Degree’s leak check may report a storage leak because main has
returned by the time the check happens. Either of these two behaviors may
be correct, depending on whether bytes was a true leak or simply a data
structure still in use when main returned.
Rather than reading the program carefully to understand when leak
detection should be performed, you can check for new leaks after a specified
number of calls to the specified procedure. Use the following options to
disable the default leak-checking and to request a leak before every 10,000th
call to the procedure proc_name:
-blocks cancel
-blocks new -every 10000 -before proc_name
Character Description
Dot (.) Indicates a longword that was never written in any of the objects,
a definite sign of wasted memory. Further analysis is generally
required to see if it is simply a deficiency of a test that never used
this field, if it is a padding problem solved by swapping fields or
choosing better types, or if this field is obsolete.
z Indicates a field whose value was always 0 (zero) in every object.
pp Indicates a pointer: that is, a 64-bit quantity that was a valid pointer
into the stack, the static data area, the heap (or was zero).
Even if an entry is listed as allocating 100 MB, it does not mean that at any
point in time 100 MB of heap storage were used by the allocated objects. It
is a cumulative figure; it indicates that this point has allocated 100 MB
over the lifetime of the program. This 100 MB may have been freed, may
have leaked, or may still be in the heap. The figure simply indicates that
this allocator has been quite active.
Ideally, the fraction of the bytes actually written should always be close to
100 percent. If it is much lower, some of what is allocated is never used. The
common reasons why a low percentage is given include the following:
• A large buffer was allocated but only a small fraction was ever used.
• Parts of every object of a given type are never used. They may be
forgotten fields or padding between real fields resulting from alignment
rules in C structures.
• Some objects have been allocated but never used at all. Sometimes leak
detection will find these objects if their pointers are discarded. However,
if they are kept on a free list, they will be found only in the heap history.
Third Degree tries to print the procedure name in the stack trace, but if the
procedure name is missing (because this is a static procedure), Third Degree
prints the program counter in the instrumented program. This information
enables you to find the location with a debugger. If the program counter is
unavailable, Third Degree prints the number of the unknown procedure.
void main()
{
double ary1[LEN];
double *ary2;
double sum = 0.0;
int i;
print_it(0.0);
else
print_it(sum);
}
****************** profsample.h: ********************
#include "profsample.h"
#include "profsample.h"
#include <stdio.h>
#include "profsample.h"
8.3.1 Techniques
The effectiveness of the automatic optimizations described in Section 10.1
is limited by the efficiency of the algorithms that the program uses. You
can further improve a program’s performance by manually optimizing its
algorithms and data structures. Such optimizations may include reducing
complexity from N-squared to log-N, avoiding copying of data, and reducing
the amount of data used. It may also extend to tuning the algorithm to
the architecture of the particular machine it will be run on — for example,
processing large arrays in small blocks such that each block remains in the
data cache for all processing, instead of the whole array being read into
the cache for each processing phase.
Tru64 UNIX supports manual optimization with its profiling tools, which
identify the parts of the application that impose the highest CPU load —
CPU cycles, cache misses, and so on. By evaluating various profiles of a
program, you can identify which parts of the program use the most CPU
resources, and you can then redesign or recode algorithms in those parts to
use less resources. The profiles also make this exercise more cost-effective
A call-graph profile shows how much CPU time is used by each procedure,
and how much is used by all the other procedures that it calls. This profile
can show which phases or subsystems in a program spend most of the
total CPU time, which can help in gaining a general understanding of the
program’s performance. This section describes two tools that provide this
information:
• The hiprof profiler (Section 8.3.2.1.1)
• The cc command’s -pg option (Section 8.3.2.1.2)
Both tools are used with the gprof tool, implicitly or explicitly, to format
and display the profile.
The optional dxprof command provides a graphical display of CPU-time
call-graph profiles.
The hiprof profiler (see hiprof(1)) instruments the program and generates
a call graph while the instrumented program executes. This profiler does
not require that the program be compiled in any particular way except as
indicated in Section 8.2. The hiprof command can generate a call-graph
profile for shared libraries and for program code, with moderate optimization
and minimal debug information. For example:
% cc -o libsample.so -shared -g1 -O2 add_vector.c mul_by_scalar.c print_it.c 1
% cc -o sample -g1 -O2 profsample.c -L. -lsample -lm 2
% hiprof -numbers -L. -inc libsample.so sample 3
The resulting sample profile is shown in Example 8–2. The call-graph profile
estimates the total cost of calling a procedure, including other procedures
that it calls. The estimation assumes that each call to a given procedure
takes the same amount of time; this may not be true in many cases, but it
is always accurate when there is only one caller.
By default, hiprof uses a low-frequency sampling technique. This can
profile all the code executed by the program, including all selected libraries.
It also provides a call-graph profile of all selected procedures (except those
in the threads-related system libraries) and detailed profiles at the level of
source lines or machine instructions (if selected).
Value = 179804.149985
------------------------------------------------------
------------------------------------------------------
3 0 2 / 2 main [1]
[4] 0.9 3 0 2 mul_by_scalar [4]
------------------------------------------------------
0 0 1 / 1 main [1]
[5] 0.0 0 0 1 print_it [5]
------------------------------------------------------
Value = 179804.149985
<spontaneous>
[1] 100.0 893310 361426982 1 __start [1]
361371860 1 / 1 main [2]
------------------------------------------------------
------------------------------------------------------
------------------------------------------------------
------------------------------------------------------
------------------------------------------------------
The cc command’s -pg option uses the same sampling technique as hiprof,
but the program needs to be instrumented by compiling with the -pg option.
(The program also needs to be compiled with the debug and optimization
options indicated in Section 8.2.) Only the executable is profiled (not shared
libraries), and few system libraries are compiled to generate a call-graph
profile; therefore, hiprof may be preferred. However, the cc command’s
-pg option and gprof are supported in a very similar way on different
vendors’ UNIX systems, so this may be an advantage. For example:
% cc -pg -o sample -g1 -O2 *.c -lm 1 % ./sample 2 % gprof
-scaled -b -numbers sample 3
The resulting sample profile is shown in Example 8–4. The gprof tool
estimates the total cost of calling a procedure (including its calls) in its
call-graph profile.
% ./sample
Value = 179804.149985
------------------------------------------------------
------------------------------------------------------
4 0 2 / 2 main [1]
[4] 1.2 4 0 2 mul_by_scalar [4]
------------------------------------------------------
0 0 1 / 1 main [1]
[5] 0.0 0 0 1 print_it [5]
------------------------------------------------------
1 For information about the -g1 and -O2 options, see Section 8.2.
2 The uprofile command runs the sample program, collecting the
performance counter data into a profile data file (named umon.out,
by default). Because prof options (-asm and -quit) are specified,
uprofile then automatically runs the prof tool to display the profile.
The -asm option provides per-instruction profiling of cycles (and other
CPU statistics, such as data cache misses, if specified). Because no
counter statistics are specified here, uprofile displays a CPU-time
profile for each instruction. The -quit 90cum% option truncates the
profile after 90 percent of the whole has been printed (see Section 8.6.3).
(Also available are the -heavy option, which reports the lines that
executed the most instructions, and the -lines option, which reports
the profile per source line within each procedure (see Section 8.6.2).
----------------------------------------------------------------------------
* -a[sm] using performance counters: *
* cycles0: 1 sample every 65536 Cycles (0.000164 seconds) *
* sorted in descending order by total time spent in each procedure; *
* unexecuted procedures excluded *
----------------------------------------------------------------------------
add_vector (add_vector.c)
0.0 0.00 0.00 0x120001260:2 addl zero, a2, a2
0.0 0.00 0.00 0x120001264:5 bis zero, zero, t0
0.0 0.00 0.00 0x120001268:5 ble a2, 0x12000131c
0.0 0.00 0.00 0x12000126c:5 subl a2, 0x3, t1
0.0 0.00 0.00 0x120001270:5 cmple t1, a2, t2
0.0 0.00 0.00 0x120001274:5 beq t2, 0x1200012f4
0.0 0.00 0.00 0x120001278:5 ble t1, 0x1200012f4
0.0 0.00 0.00 0x12000127c:5 subq a0, a1, t3
0.0 0.00 0.00 0x120001280:5 lda t3, 31(t3)
0.0 0.00 0.00 0x120001284:5 cmpule t3, 0x3e, t3
0.0 0.00 0.00 0x120001288:5 bne t3, 0x1200012f4
0.0 0.00 0.00 0x12000128c:5 ldq_u zero, 0(sp)
20.2 6.45 6.45 0x120001290:6 ldl zero, 128(a1)
1.3 0.42 6.87 0x120001294:6 lds $f31, 128(a0)
35.6 11.39 18.26 0x120001298:6 ldt $f0, 0(a1)
20.0 6.40 24.66 0x12000129c:6 ldt $f1, 0(a0)
9.7 3.10 27.75 0x1200012a0:6 ldt $f10, 8(a1)
14.9 4.77 32.53 0x1200012a4:6 ldt $f11, 8(a0)
17.4 5.56 38.09 0x1200012a8:6 ldt $f12, 16(a1)
7.0 2.26 40.35 0x1200012ac:6 ldt $f13, 16(a0)
8.2 2.62 42.97 0x1200012b0:6 ldt $f14, 24(a1)
12.9 4.14 47.11 0x1200012b4:6 ldt $f15, 24(a0)
24.9 7.97 55.09 0x1200012b8:6 addt $f1,$f0,$f0
24.7 7.92 63.01 0x1200012bc:6 addt $f11,$f10,$f10
37.8 12.12 75.13 0x1200012c0:6 addt $f13,$f12,$f12
39.2 12.54 87.67 0x1200012c4:6 addt $f15,$f14,$f14
0.8 0.26 87.93 0x1200012c8:5 addl t0, 0x4, t0
0.0 0.00 87.93 0x1200012cc:5 lda a1, 32(a1)
8.4 2.68 90.61 0x1200012d0:6 stt $f0, 0(a0)
----------------------------------------------------------------------------
* -a[sm] using performance counters: *
* dcacheldmiss: 1 sample every 16384 DCache LD Misses 1 *
* sorted in descending order by samples recorded for each procedure; *
* unexecuted procedures excluded *
----------------------------------------------------------------------------
add_vector (add_vector.c)
0.0 0.00 0.00 0x120001260:2 addl zero, a2, a2
0.0 0.00 0.00 0x120001264:5 bis zero, zero, t0
0.0 0.00 0.00 0x120001268:5 ble a2, 0x12000131c
0.0 0.00 0.00 0x12000126c:5 subl a2, 0x3, t1
0.0 0.00 0.00 0x120001270:5 cmple t1, a2, t2
0.0 0.00 0.00 0x120001274:5 beq t2, 0x1200012f4
0.0 0.00 0.00 0x120001278:5 ble t1, 0x1200012f4
0.0 0.00 0.00 0x12000127c:5 subq a0, a1, t3
0.0 0.00 0.00 0x120001280:5 lda t3, 31(t3)
0.0 0.00 0.00 0x120001284:5 cmpule t3, 0x3e, t3
0.0 0.00 0.00 0x120001288:5 bne t3, 0x1200012f4
0.0 0.00 0.00 0x12000128c:5 ldq_u zero, 0(sp)
1.0 0.18 0.18 0x120001290:6 ldl zero, 128(a1)
3.0 0.55 0.73 0x120001294:6 lds $f31, 128(a0)
62.0 11.27 12.00 0x120001298:6 ldt $f0, 0(a1) 3
64.0 11.64 23.64 0x12000129c:6 ldt $f1, 0(a0)
8.0 1.45 25.09 0x1200012a0:6 ldt $f10, 8(a1)
47.0 8.55 33.64 0x1200012a4:6 ldt $f11, 8(a0)
13.0 2.36 36.00 0x1200012a8:6 ldt $f12, 16(a1)
38.0 6.91 42.91 0x1200012ac:6 ldt $f13, 16(a0)
15.0 2.73 45.64 0x1200012b0:6 ldt $f14, 24(a1)
51.0 9.27 54.91 0x1200012b4:6 ldt $f15, 24(a0)
49.0 8.91 63.82 0x1200012b8:6 addt $f1,$f0,$f0
142.0 25.82 89.64 0x1200012bc:6 addt $f11,$f10,$f10
13.0 2.36 92.00 0x1200012c0:6 addt $f13,$f12,$f12
1 The stated sampling rate of 1 sample every 16384 means that each
sample shown in the profile occurred after 16384 data cache misses, but
not all of these occurred at the instruction indicated.
2 The total number of samples is shown, not the number of data cache
misses.
3 Indicates the number of samples recorded at an instruction, which
statistically implies a proportionate number of data cache misses.
Value = 179804.149985
% ./sample
Value = 179804.149985
----------------------------------------------------------------------------
* -p[rocedures] using pc-sampling; *
* sorted in descending order by total time spent in each procedure; *
* unexecuted procedures excluded *
----------------------------------------------------------------------------
˝
----------------------------------------------------------------------------
* -h[eavy] using pc-sampling; *
* sorted in descending order by time spent in each source line; *
* unexecuted lines excluded *
----------------------------------------------------------------------------
The pixie tool (see pixie(1)) can also profile source-lines and instructions
(including shared libraries), but note that when it displays counts of cycles,
it is actually reporting counts of instructions executed, not machine cycles.
Its −truecycles 2 option can estimate the number of cycles that would be
used if all memory accesses were satisfied by the cache, but programs can
rarely cache enough of their data for this to be accurate, and only the Alpha
EV4 and EV5 families can be fully simulated in this way. For example:
% cc -o sample -g1 -O2 *.c -lm 1
% pixie -all -proc -heavy -quit 5 sample 2
1 For information about the -g1 and -O2 options, see Section 8.2.
2 The pixie command creates an instrumented version of the program
(sample.pixie) and an instruction-addresses file (sample.Addrs).
Because prof options (-proc, -heavy, -quit) are specified,
pixie automatically runs that instrumented program to create an
Value = 179804.149985
----------------------------------------------------------------------------
* -p[rocedures] using basic-block counts; *
* sorted in descending order by the number of cycles executed in each *
* procedure; unexecuted procedures are excluded *
----------------------------------------------------------------------------
----------------------------------------------------------------------------
8.4.1 Techniques
The techniques described in the previous sections can improve an
application’s use of just the CPU. You can make further performance
enhancements by improving the efficiency with which the application uses
the other components of the computer system, such as heap memory, disk
files, network connections, and so on.
As with CPU profiling, the first phase of a resource usage improvement
process is to monitor how much memory, data I/O and disk space, elapsed
time, and so on, is used. The throughput of the computer can then be
The Tru64 UNIX base system commands ps u, swapon -s, and vmstat 3
can show the currently active processes’ usage of system resources such as
CPU time, physical and virtual memory, swap space, page faults, and so on.
See ps(1), swapon(8), and vmstat(3) for more information.
The optional pview command provides a graphical display of similar
information for the processes that comprise an application. See pview(1).
The time commands provided by the Tru64 UNIX system and command
shells provide an easy way to measure the total elapsed and CPU times for a
program and it descendants. See time(1).
Performance Manager is an optional system performance monitoring and
management tool with a graphical interface. See pmgr(8X).
For more information about related tools, see the System Configuration
and Tuning manual.
The Third Degree tool (see third(1)) reports heap memory leaks in a
program, by instrumenting it with the Third Degree memory-usage checker,
running it, and displaying a log of leaks detected at program exit. For
example:
1 Full debug information (that is, compiling with the -g option) is usually
best for Third Degree, but if less is available, the reports will just be
machine-level instead of source-level. The -g1 option is fine if you are
just checking for memory leaks.
2 The third command creates an instrumented version of the program
(sample.third). Because the -display option is specified, third
automatically runs that instrumented program to create a log file
(sample.3log) and then runs more to display the file.
Value = 179804.149985
-----------------------------------------------------------------------
------------------------------------------------------------------------
------------------------------------------------------------------------
New blocks in heap after program exit
800000 bytes in 1 leak (including 1 not referenced by other leaks) created at:
malloc sample
main sample, profsample.c, line 19
__start sample
------------------------------------------------------------------------
------------------------------------------------------------------------
memory layout at program exit
heap 933888 bytes [0x140012000-0x1400f6000]
stack 819504 bytes [0x11ff37ed0-0x120000000]
sample data 66464 bytes [0x140000000-0x1400103a0]
sample text 802816 bytes [0x120000000-0x1200c4000]
=============================================================================
Third Degree can also detect various kinds of bugs that may be affecting
the correctness or performance of a program. See Chapter 7 for more
information on debugging and leak detection.
The optional dxheap command provides a graphical display of Third
Degree’s heap and bug reports. See dxheap(1).
The optional mview command provides a graphical analysis of heap usage
over time. This view of a program’s heap can clearly show the presence
(if not the cause) of significant leaks or other undesirable trends such as
wasted memory. See mview(1).
8.5.1 Techniques
Most of the profiling techniques described in the previous sections are
effective only if you profile and optimize or tune the parts of the program
that are executed in the scenarios whose performance is important. Careful
selection of the data used for the profiled test runs is often sufficient, but you
Similarly, the −zero option reports the names of procedures that were never
executed. Conversely, pixie’s −p[rocedure], −h[eavy], and −a[sm] options
show which procedures, source lines, and instructions were executed.
If multiple test runs are needed to build up a typical scenario, the prof
command can be run separately on a set of profile data files. For example:
% cc -o sample -g1 -O2 *.c -lm 1
% pixie -pids sample 2
% ./sample.pixie 3
% ./sample.pixie
% prof -pixie -t sample sample.Counts.* 4
1 For information about the -g1 and -O2 options, see Section 8.2.
2 The pixie command creates an instrumented version of the program
(sample.pixie) and an instruction-addresses file (sample.Addrs).
The -pids option adds the process ID of the instrumented program’s
test run (item 3) to the name of the profiling data file produced, so that
a unique file is retained after each run. For information about working
with multiple data files, see Section 8.7.
3 The instrumented program is run twice (usually with different input
data) to produce two profiling data files named sample.Counts.pid.
4 The -pixie option tells prof to use pixie mode rather than the default
PC-sampling mode. The prof tool uses the sample.Addrs file and the
two sample.Counts.pid files to create the profile from the two runs.
The −exclude option prints profiling information for all procedures except
the specified procedure. You can use this option several times on the
command line. Do not use −only and −exclude together on the same
command line.
Many of the prof profiling options print output as percentages; for example,
the percentage of total execution time attributed to a particular procedure.
By default, the −only and −exclude options cause prof to calculate
percentages based on all of the procedures in the application even if they
were omitted from the listing. You can change this behavior with the −Only
and −Exclude options. They work the same as −only and −exclude, but
cause prof to calculate percentages based only on those procedures that
appear in the listing.
The −totals option, used with the −procedures and −invocations
listings, prints cumulative statistics for the entire object file instead of for
each procedure in the object.
If you specify several modes on the same command line, −quit affects the
output from each mode. The following command prints only the 20 most
time-consuming procedures and the 20 most time-consuming source lines:
% pixie -procedures -heavy -quit 20 sample
Depending on the profiling mode, the total can refer to the total amount
of time, the total number of executed instructions, or the total number
of invocation counts.
By default, when you make multiple profiling runs, each run overwrites
the existing data file in the working directory. Each tool has options for
renaming data files so they can be preserved from run to run. The hiprof,
pixie, and uprofile commands have the following options:
-dirname path Specifies a directory where the data file is to be created.
-pids Adds the process ID of the instrumented program’s
run to the data file name.
Then, when using the gprof command, you can specify a wildcard to include
all the profiling data files in the directory:
% gprof -b sample profdata/*
Note that PROFFLAGS affects the profiling behavior of a program during its
execution; it has no effect on the prof and gprof postprocessors. When you
set PROFFLAGS to a null string, no profiling occurs.
For more information about file-naming conventions, see the tool reference
pages. See Section 8.8 for the file-naming conventions for multithreaded
programs.
One merge technique is to specify the name of each data file explicitly on
the command line. For example, the following command prints profiling
information from two profile data files generated using hiprof:
% gprof sample sample.1510.hiout sample.1522.hiout
At a later time, you can then display profiling data using the combined file,
just as you would use a normal mon.out file. For example:
% prof -procedures sample total.out
The merge process is similar for −pixie mode. You must specify the
executable file’s name, the .Addrs file, and each .Counts file. For example:
% prof -pixie -merge total.Counts a.out a.out.Addrs \
a.out.Counts.1866 a.out.Counts.1868
If the application uses monitor( ) and allocates separate buffers for each
thread profiled, you must first set PROFFLAGS to "-disable_default
-threads" because this setting affects the file-naming conventions that are
used. Without the −threads option, the buffer and address range used as a
result of the first monitor or monstartup call would be applied to every
thread that subsequently requests profiling. In this case, a single data file
that covers all threads being profiled would be created.
Each thread in a process must call the monitor( ) or monstartup( )
routines to initiate profiling for itself.
You can use monitor and monstartup to profile an address range in each
shared library as well as in the static executable.
For more information on these functions, see monitor(3).
By default, profiling begins as soon your program starts to execute.
To prevent this behavior, set the PROFFLAGS environment variable to
−disable_default, as shown in the following C shell example:
setenv PROFFLAGS "-disable_default"
Then, you can use the monitor routines to begin profiling after the first call
to monitor or monstartup.
Example 8–11 demonstrates how to use the monstartup and monitor
routines within a program to begin and end profiling.
#include <stdio.h>
#include <sys/syslimits.h>
char dir[PATH_MAX];
main( )
{
int i;
int a = 1;
*/
monstartup(_ _start,&_etext);
for(i=0;i<10;i++)
domath( );
monitor(0);
}
domath( )
{
int i;
double d1, d2;
d2 = 3.1415;
for (i=0; i<1000000; i++)
d1 = sqrt(d2)*sqrt(d2);
}
The external name _etext lies just above all the program text. See end(3)
for more information.
When you set the PROFFLAGS environment variable to −disable_default,
you disable default profiling buffer support. You can allocate buffers within
your program, as shown in Example 8–12.
#include <sys/types.h>
#include <sys/syslimits.h>
void domath(void);
void nextproc(void);
char dir[PATH_MAX];
main( )
{
int i;
char *buffer;
size_t bufsize;
buffer = calloc(bufsize,1);
/* Start sampling. */
monitor(domath,nextproc,buffer,bufsize,0);
for(i=0;i<10;i++)
domath( );
d2 = 3.1415;
for (i=0; i<1000000; i++)
d1 = sqrt(d2)*sqrt(d2);
}
void nextproc(void)
{}
#include <signal.h>
main()
{
int i;
double d1, d2;
/*
* Declare monitor_signal() as signal handler for SIGUSR1
*/
signal(SIGUSR1,monitor_signal);
d2 = 3.1415;
/*
* Loop infinitely (absurd example of non-terminating process)
*/
for (;;)
d1 = sqrt(d2)*sqrt(d2);
}
Program analysis tools are extremely important for computer architects and
software engineers. Computer architects use them to test and measure new
architectural designs, and software engineers use them to identify critical
pieces of code in programs or to examine how well a branch prediction or
instruction scheduling algorithm is performing. Program analysis tools
are needed for problems ranging from basic block counting to data cache
simulation. Although the tools that accomplish these tasks may appear
quite different, each can be implemented simply and efficiently through
code instrumentation.
Atom provides a flexible code instrumentation interface that is capable
of building a wide variety of tools. Atom separates the common part in
all problems from the problem-specific part by providing machinery for
instrumentation and object-code manipulation, and allowing the tool
designer to specify what points in the program are to be instrumented. Atom
is independent of any compiler and language as it operates on object modules
that make up the complete program.
This chapter discusses the following topics:
• How to run installed Atom tools and new Atom tools that are still under
development (Section 9.1).
• How to develop specialized Atom tools (Section 9.2).
You can have multiple instrumentation and analysis source files. The
following example creates composite instrumentation and analysis objects
from several source files:
% cc -c file1.c file2.c
% cc -c file7.c file8
% ld -r -o tool.inst.o file1.o file2.o
% ld -r -o tool.anal.o file7.o file8.o
% atom hello tool.inst.o tool.anal.o -o hello.atom
-debug
Lets you debug instrumentation routines by causing Atom to transfer
control to the symbolic debugger at the start of the instrumentation
-ladebug
Lets you debug instrumentation routines with the optional ladebug
debugger, if installed on your system. Atom puts the control in
ladebug with a stop at the instrumentation routine. Use ladebug
if the instrumentation routines contain C++ code. See the Ladebug
Debugger Manual for more information.
-ga (-g)
Produces the instrumented program with debugging information. This
option lets you debug analysis routines with a symbolic debugger. The
default -A0 option (not -A1) is recommended with -ga (or -g). For
example:
% atom hello ptrace.inst.c ptrace.anal.c -o hello.ptrace -ga
% dbx hello.ptrace
dbx version 3.11.8
Type ’help’ for help.
(dbx) stop in ProcTrace
[2] stop in ProcTrace
(dbx) r
[2] stopped at [ProcTrace:5 ,0x120005574] fprintf (stderr,"%s\n",name);
(dbx) n
__start
[ProcTrace:6 ,0x120005598] }
-gap
Produces the instrumented program with debugging information.
This enables debugging of analysis and application routines. The
prefix “_APP_” is attached to all variable and procedure names in the
application. The default -A0 option (not -A1) is recommended when
-gpa is used.
-gp
Produces the instrumented program with debugging information. This
option lets you debug application routines with a symbolic debugger.
−pthread
Specifies that thread-safe support is required. This option should be
used when instrumenting threaded applications.
-toolargs
Passes arguments to the Atom tool’s instrumentation routine. Atom
passes the arguments in the same way that they are passed to C
programs, using the argc and argv arguments to the main program.
For example:
#include <stdio.h>
unsigned InstrumentAll(int argc, char **argv) {
int i;
for (i = 0; i < argc; i++) {
printf(stderr,"argv[%d]: %s\n",argv[i]);
}
}
The following example shows how Atom passes the −toolargs
arguments:
% atom hello args.inst.c -toolargs="8192 4"
argv[0]: hello
argv[1]: 8192
argv[2]: 4
Atom calls the Instrument routine for each object in the application
program. As a result, an Instrument routine does not need to use the
object navigation routines (such as GetFirstObj). Because Atom
automatically writes each modified object before passing the next to
the Instrument routine, the Instrument routine should never call
the BuildObj, WriteObj, or ReleaseObj routine. When using the
Instrument interface, you can define an InstrumentInit routine
to perform tasks required before Atom calls Instrument for the first
object (such as defining analysis routine prototypes, adding program
level instrumentation calls, and performing global initializations).
You can also define an InstrumentFini routine to perform tasks
required after Atom calls Instrument for the last object (such as
global cleanup).
Atom calls the InstrumentAll routine once for the entire application
program, which allows a tool’s instrumentation code itself to
determine how to traverse the application’s objects. With this method,
there are no InstrumentInit or InstrumentFini routines. An
InstrumentAll routine must call the Atom object navigation routines
and use the BuildObj, WriteObj, or ReleaseObj routine to manage
the application’s objects.
Table 9–3 lists the routines that provide information about an object’s
procedures.
Table 9–4 lists the routines that provide information about a procedure’s
basic blocks.
Table 9–5 lists the routines that provide information about a basic block’s
instructions.
9.2.5.1 Input/Output
The standard I/O library provided to analysis routines does not automatically
flush and close streams when the instrumented program terminates, so
the analysis code must flush or close them explicitly when all output has
been completed. Also, the stdout and stderr streams that are provided
to analysis routines will be closed when the application calls exit(), so
analysis code may need to duplicate one or both of these streams if they
need to be used after application exit (for example, in a ProgramAfter or
ObjAfter analysis routine — see AddCallProto(5)).
For output to stderr (or a duplicate of stderr) to appear immediately,
analysis code should call setbuf(stream,NULL) to make the stream
unbuffered or call fflush after each set of fprintf calls. Similarly,
analysis routines using C++ streams can call cerr.flush().
If a process calls a fork function but does not call an exec function, the
process is cloned and the child inherits an exact copy of the parent’s state.
In many cases, this is exactly the behavior that an Atom tool expects.
For example, an instruction-address tracing tool sees references for both
the parent and the child, interleaved in the order in which the references
occurred.
/*
* Create an XLATE structure for this Obj. We use this to translate
* instrumented jump target addresses to pure jump target addresses.
*/
pxlt = CreateXlate(obj, XLATE_NOSIZE);
for (; i; i = GetNextInst(i)) {
bin.word = GetInstInfo(i, InstBinary);
if (bin.common.opcode == op_jsr &&
bin.j_format.function == jsr_jmp)
{
/*
* This is a jump instruction. Instrument it.
*/
AddCallInst(i, InstBefore, "JmpLog", InstPC(i),
GetInstInfo(i, InstRB));
}
}
}
}
/*
* Re-prototype the RegisterXlate() analysis routine now that we
* know the size of the pure address array.
*/
sprintf(proto, "RegisterXlate(int, XLATE *, long[%d])", address_num());
AddCallProto(proto);
/*
* Pass the XLATE and the pure address array to this object.
*/
AddCallObj(obj, ObjBefore, "RegisterXlate", GetObjInfo(obj, ObjID),
pxlt, address_paddrs());
/*
* Deallocate the pure address array.
*/
address_free();
}
/*
** Maintains a dynamic array of pure addresses.
*/
static unsigned long * pAddrs;
static unsigned maxAddrs = 0;
static unsigned nAddrs = 0;
/*
/*
* Add the address to the array.
*/
pAddrs[nAddrs++] = addr;
}
/*
** Return the number of elments in the address array.
*/
static unsigned address_num(void)
{
return(nAddrs);
}
/*
** Return the array of addresses.
*/
static unsigned long *address_paddrs(void)
{
return(pAddrs);
}
/*
** Deallocate the address array.
*/
static void address_free(void)
{
free(pAddrs);
pAddrs = 0;
maxAddrs = 0;
nAddrs = 0;
}
/*
* Each object in the application gets one of the following data
* structures. The XLATE contains the instrumented addresses for
* all possible jump targets in the object. The array contains
* the matching pure addresses.
/*
* An array with one ObjXlt_t structure for each object in the
* application.
*/
static ObjXlt_t * pAllXlts;
static unsigned nObj;
static int translate_addr(unsigned long, unsigned long *);
static int translate_addr_obj(ObjXlt_t *, unsigned long,
unsigned long *);
/*
** Called at ProgramBefore. Registers the number of objects in
** this application.
*/
void RegisterNumObjs(
unsigned nobj)
{
/*
* Allocate an array with one element for each object. The
* elements are initialized as each object is loaded.
*/
nObj = nobj;
pAllXlts = calloc(nobj, sizeof(pAllXlts));
if (!pAllXlts) {
fprintf(stderr, "Out of Memory\n");
exit(1);
}
}
/*
** Called at ObjBefore for each object. Registers an XLATE with
** instrumented addresses for all possible jump targets. Also
** passes an array of pure addresses for all possible jump targets.
*/
void RegisterXlate(
unsigned iobj,
XLATE * pxlt,
unsigned long * paddrs_pure)
{
/*
* Initialize this object’s element in the pAllXlts array.
*/
pAllXlts[iobj].pXlt = pxlt;
pAllXlts[iobj].pAddrsPure = paddrs_pure;
}
/*
** Called at InstBefore for each jump instruction. Prints the pure
** target address of the jump.
*/
void JmpLog(
unsigned long pc,
REGV targ)
{
unsigned long addr;
/*
** Attempt to translate the given instrumented address to its pure
** equivalent. Set ’*paddr_pure’ to the pure address and return 1
** on success. Return 0 on failure.
**
** Will always succeed for jump target addresses.
*/
static int translate_addr(
unsigned long addr_inst,
unsigned long * paddr_pure)
{
unsigned long start;
unsigned long size;
unsigned i;
/*
* Find out which object contains this instrumented address.
*/
for (i = 0; i < nObj; i++) {
start = XlateInstTextStart(pAllXlts[i].pXlt);
size = XlateInstTextSize(pAllXlts[i].pXlt);
if (addr_inst >= size && addr_inst < start + size) {
/*
* Found the object, translate the address using that
* object’s data.
*/
return(translate_addr_obj(&pAllXlts[i], addr_inst,
paddr_pure));
}
}
/*
* No object contains this address.
*/
return(0);
}
/*
** Attempt to translate the given instrumented address to its
** pure equivalent using the given object’s translation data.
** Set ’*paddr_pure’ to the pure address and return 1 on success.
** Return 0 on failure.
*/
static int translate_addr_obj(
ObjXlt_t * pObjXlt,
unsigned long addr_inst,
unsigned long * paddr_pure)
{
unsigned num;
unsigned i;
/*
* See if the instrumented address matches any element in the XLATE.
*/
num = XlateNum(pObjXlt->pXlt);
for (i = 0; i < num; i++) {
if (XlateAddr(pObjXlt->pXlt, i) == addr_inst) {
/*
* Matches this XLATE element, return the matching pure
/*
* No match found, must not be a possible jump target.
*/
return(0);
}
The ptrace tool prints the names of procedures in the order in which they
are executed. The implementation adds a call to each procedure in the
application. By convention, the instrumentation for the ptrace tool is
placed in the file ptrace.inst.c. For example:
1 #include <stdio.h>
2 #include <cmplrs/atom.inst.h> 1
3
4 unsigned InstrumentAll(int argc, char **argv) 2
5 {
6 Obj *o; Proc *p;
7 AddCallProto("ProTrace(char *)"); 3
8 for (o = GetFirstObj(); o != NULL; o = GetNextObj(o)) { 4
9 if (BuildObj(o) return 1; 5
10 for (p = GetFirstObjProc(o); p != NULL; p = GetNextProc(p)) { 6
11 const char *name = ProcName(p); 7
12 if (name == NULL) name = "UNKNOWN"; 8
13 AddCallProc(p,ProcBefore,"ProcTrace",name); 9
14 }
15 WriteObj(o); 10
16 }
17 return(0);
18 }
The following example repeats this process with the application linked
call-shared. The major difference is that the LD_LIBRARY_PATH
environment variable must be set to the current directory because Atom
creates an instrumented version of the libc.so shared library in the local
directory.
% cc hello.c -o hello
% atom hello ptrace.inst.c ptrace.anal.c -o hello.ptrace -all
% setenv LD_LIBRARY_PATH ‘pwd‘
% hello.ptrace
__start
_call_add_gp_range
__exc_add_gp_range
malloc
cartesian_alloc
cartesian_growheap2
__getpagesize
__sbrk
.
.
.
The call-shared version of the application calls almost twice the number of
procedures that the nonshared version calls.
Note that only calls in the original application program are instrumented.
Because the call to the ProcTrace analysis procedure did not occur in
the original application, it does not appear in a trace of the instrumented
3 static int n = 0;
4
5 static const char * SafeProcName(Proc *);
6
7 void InstrumentInit(int argc, char **argv)
8{
9 AddCallProto("OpenFile(int)"); 1
10 AddCallProto("ProcedureCalls(int)");
11 AddCallProto("ProcedureCount(int,int)");
12 AddCallProto("ProcedurePrint(int,char*)");
13 AddCallProto("CloseFile()");
14 AddCallProgram(ProgramAfter,"CloseFile"); 2
15 }
16
17 Instrument(int argc, char **argv, Obj *obj)
18 {
19 Proc *p; Block *b;
20
21 for (p = GetFirstObjProc(obj); p != NULL; p = GetNextProc(p)) { 3
22 AddCallProc(p,ProcBefore,"ProcedureCalls",n);
23 for (b = GetFirstBlock(p); b != NULL; b = GetNextBlock(b)) { 4
24 AddCallBlock(b,BlockBefore,"ProcedureCount", 5
25 n,GetBlockInfo(b,BlockNumberInsts));
26 }
27 AddCallObj(obj, ObjAfter,"ProcedurePrint",n,SafeProcName(p)); 6
28 n++; 7
29 }
30 }
31
32 void InstrumentFini(void)
33 {
34 AddCallProgram(ProgramBefore,"OpenFile",n); 8
35 }
36
37 static const char *SafeProcName(Proc *p)
The analysis procedures used by the iprof tool are defined in the
iprof.anal.c file as shown in the following example:
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5
6 long instrTotal = 0;
7 long *instrPerProc;
8 long *callsPerProc;
9
10 FILE *OpenUnique(char *fileName, char *type)
After the instrumentation and analysis files are specified, the tool is
complete. To demonstrate the application of this tool, compile and link the
"Hello" application as follows:
#include <stdio.h>
main()
{
printf("Hello world!\n");
}
Total 8750
% unsetenv LD_LIBRARY_PATH
Instruction and data address tracing has been used for many years as a
technique to capture and analyze cache behavior. Unfortunately, current
machine speeds make this increasingly difficult. For example, the Alvinn
SPEC92 benchmark executes 961,082,150 loads, 260,196,942 stores, and
73,687,356 basic blocks, for a total of 2,603,010,614 Alpha instructions.
Storing the address of each basic block and the effective address of all the
loads and stores would take in excess of 10 GB and slow down the application
by a factor of over 100.
The analysis procedures used by the cache tool are defined in the
cache.anal.c file as shown in the following example:
1 #include <stdio.h>
2 #include <assert.h>
3 #define CACHE_SIZE 8192
4 #define BLOCK_SHIFT 5
5 long tags[CACHE_SIZE >> BLOCK_SHIFT];
6 long references, misses;
7
8 void Reference(long address) {
9 int index = (address & (CACHE_SIZE-1)) >> BLOCK_SHIFT;
10 long tag = address >> BLOCK_SHIFT;
11 if tags[index] != tag) {
12 misses++;
13 tags[index] = tag;
14 }
15 references++;
16 }
17 void Print() {
18 FILE *file = fopen("cache.out","w");
19 assert(file != NULL);
20 fprintf(file,"References: %ld\n", references);
21 fprintf(file,"Cache Misses: %ld\n", misses);
22 fprintf(file,"Cache Miss Rate: %f\n", (100.0 * misses) / references);
23 fclose(file);
24 }
The following example applies the cache tool to instrument both the
nonshared and call-shared versions of the application:
% cc hello.c -o hello
% atom hello cache.inst.c cache.anal.c -o hello.cache -all
% setenv LD_LIBRARY_PATH ‘pwd‘
% hello.cache
Hello world!
% more cache.out
References: 1091
Cache Misses: 225
Cache Miss Rate: 20.623281
% cc -non_shared hello.c -o hello
% atom hello cache.inst.c cache.anal.c -o hello.cache -all
% hello.cache
Hello world!
% more cache.out
References: 382
Cache Misses: 93
Cache Miss Rate: 24.345550
−speculate all
−speculate by_routine
Option Description
-arch Specifies which version of the Alpha architecture to
generate instructions for. See -arch in cc(1) for an
explanation of the differences between -arch and -tune.
−ansi_alias Specifies whether source code observes ANSI C
aliasing rules. ANSI C aliasing rules allow for
more aggressive optimizations.
−ansi_args Specifies whether source code observes ANSI C rules
about arguments. If ANSI C rules are observed, special
argument-cleaning code does not have to be generated.
−fast Turns on the optimizations for the following options for
increased performance:
−ansi_alias
−ansi_args
−assume trusted_short_alignment
−D_FASTMATH
−float
−fp_reorder
−ifo
−D_INLINE_INTRINSICS
−D_INTRINSICS
-intrinsics
−O3
−readonly_strings
−feedback Specifies that the compiler should use the profile
information contained in the specified file when
performing optimizations. For more information,
see Section 10.1.3.2.
−fp_reorder Specifies whether certain code transformations that
affect floating-point operations are allowed.
−G Specifies the maximum byte size of data items in the
small data sections (sbss or sdata).
−inline Specifies whether to perform inline expansion of functions.
−ifo Provides improved optimization (interfile optimization)
and code generation across file boundaries that would not
be possible if the files were compiled separately.
−O Specifies the level of optimization that is to be
achieved by the compilation.
The spike tool performs code optimization after linking. Because it can
operate on an entire program, spike is able to do optimizations that the
compiler cannot do. spike is most effective when it uses profile information
to guide optimization, as discussed in Section 10.1.3.2.
spike is new with Tru64 UNIX Version 5.1 and is intended to replace om
and cord. It provides better control and more effective optimization, and it
can be used with both executables and shared libraries. spike cannot be
used with om or cord. For information about om and cord, see Appendix F.
Example 1
In this example, spike is applied to the binary my_prog, producing the
optimized output file prog1.opt.
% spike my_prog -o prog1.opt
Example 2
In this example, spike is applied during compilation with the cc command’s
-spike option:
% cc -c file1.c
% cc -o prog3 file1.o -spike
Example 3
This example shows the three basic steps for profile-directed optimization
with spike: (1) preparing the program for optimization, (2) creating an
instrumented version of the program and running it to collect profiling
statistics, and (3) feeding that information back to the compiler and
linker to help them optimize the executable code. Later examples show
how to elaborate on these steps to accommodate ongoing changes during
development and data from multiple profiling runs.
% cc -feedback prog -o prog -O3 *.c 1
% pixie -update prog 2
% cc -feedback prog -o prog -spike -O3 *.c 3
1 When the program is compiled with the -feedback option for the
first time, a special augmented executable file is created. It contains
Example 5
You might want to run your instrumented program several times with
different inputs to get an accurate picture of its profile. This example
shows how to optimize a program by merging profiling statistics from two
instrumented runs of a program, prog, whose output varies from run to run
with different sets of input:
% cc -feedback prog -o prog *.c 1
% pixie -pids prog 2
% prog.pixie 3
(input set 1)
% prog.pixie
(input set 2)
% prof -pixie -update prog prog.Counts.* 4
% spike prog -feedback prog -o prog.opt 5
The -spike option requires that you relink the program. When using the
spike command, you do not have to link the program a second time to
invoke spike.
Example 6
This example differs from Example 5 in that a normal (unaugmented)
executable is created, and the spike command’s -fb option (rather than the
-feedback option) is used:
% cc prog -o prog *.c
% pixie -pids prog
% prog.pixie
(input set 1)
% prog.pixie
(input set 2)
% prof -pixie -merge prog.Counts prog prog.Addrs prog.Counts.*
% spike prog -fb prog -o prog.opt
The prof -pixie -merge command merges the two data files from the
two instrumented runs into one combined prog.Counts file. With this form
of feedback, the -g1 option must be specified explicitly to provide optimum
symbolization for profiling.
The spike -fb command uses the information in prog.Addrs and
prog.Counts to produce the optimized output file prog.opt.
The method of Example 5 is preferred. The method in Example 6 is supported
for compatibility and should be used only if you cannot compile with the
-feedback option that uses feedback information stored in the executable.
You can activate the direct I/O feature for use on an AdvFS file for both AIO
and non-AIO applications. To activate the feature, use the open function in
an application, setting the O_DIRECTIO file access flag. For example:
open ("file", O_DIRECTIO | O_RDWR, 0644)
Direct I/O mode remains in effect until the file is closed by all users.
The fcntl( ) function with the parameter F_GETCACHEPOLICY can be
used to return the caching policy of a file, either FCACHE or FDIRECTIO
mode. For example:
int fcntlarg = 0;
ret = fcntl( filedescriptor, F_GETCACHEPOLICY, &fcntlarg );
if ( ret != -1 && fcntlarg == FDIRECTIO ) {
.
.
.
For details on the use of direct I/O and AdvFS, see fcntl(2) and open(2).
Source Code:
int len = 10;
char a[10];
void zero()
{
char *p;
for (p = a; p != a + len; ) *p++ = 0;
}
void azero()
{
int i;
for (i = 0; i != len; i++) a[i] = 0;
}
• Use local variables. As shown in the following example, specifying len
as a local variable or formal argument ensures that aliasing cannot take
place and permits the compiler to place len in a register:
Source Code:
char a[10];
void
lpzero(len)
int len;
{
char *p;
for (p = a; p != a + len; ) *p++ = 0;
}
exc_add_pc_range_table
exc_remove_pc_range_table
exc_lookup_function_table_address
exc_lookup_function_entry
find_rpd
exc_add_gp_range
exc_remove_gp_range
exc_lookup_gp
The C language structured exception handler calls routines in the last two
categories to allow user code to fix up an exception and resume execution,
and to locate and dispatch to a user-defined exception handler. Section 11.3
describes this process. For more information on any routine provided in
/usr/ccs/lib/cmplrs/cc/libexc.a, see the routine’s reference page.
}
except ( exception-filter) {
exception-handler
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <excpt.h>
void main(void)
{
struct sigaction act, oldact;
char *x=0;
/*
* Set up things so that SIGSEGV signals are delivered. Set
* exc_raise_signal_exception as the SIGSEGV signal handler
* in sigaction.
*/
act.sa_handler = exc_raise_signal_exception;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (sigaction(SIGSEGV, &act, &oldact) < 0)
perror("sigaction:");
/*
* If a segmentation violation occurs within the following try
* block, the run-time exception dispatcher calls the exception
* filter associated with the except statement to determine
* whether to call the exception handler to handle the SIGSEGV
* signal exception.
*/
try {
*x=55;
}
/*
* The exception filter tests the exception code against
* SIGSEGV. If it tests true, the filter returns 1 to the
* dispatcher, which then executes the handler; if it tests
* false, the filter returns -1 to the dispatcher, which
* continues its search for a handler in the previous run-time
* stack frames. Eventually the last-chance handler executes.
* Note: Normally the printf in the filter would be replaced
* with a call to a routine that logged the unexpected signal.
*/
except(exception_code() == EXC_VALUE(EXC_SIGNAL,SIGSEGV) ? 1 :
(printf("unexpected signal exception code 0x%lx\n",
exception_code()), 0))
{
printf("segmentation violation reported: handler\n");
exit(0);
}
printf("okay\n");
exit(1);
}
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <excpt.h>
#include <machine/fpu.h>
#include <errno.h>
int main(void)
{
Exception_info_ptr except_info;
system_exrec_type exception_record;
long code;
struct sigaction act, oldact;
unsigned long float_traps=IEEE_TRAP_ENABLE_DZE;
double temperature=75.2, divisor=0.0, quot, return_val;
/*
* Set up things so that IEEE DZO traps are reported and that
* SIGFPE signals are delivered. Set exc_raise_signal_exception
* as the SIGFPE signal handler.
*/
act.sa_handler = exc_raise_signal_exception;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (sigaction(SIGFPE, &act, &oldact) < 0)
perror("sigaction:");
ieee_set_fp_control(float_traps);
/*
* If a floating divide-by-zero FPE occurs within the following
* try block, the run-time exception dispatcher calls the
* exception filter associated with the except statement to
* determine whether the SIGFPE signal exception is to be
* handled by the exception handler.
*/
try {
printf("quot = IEEE %.2f / %.2f\n",temperature,divisor);
quot = temperature / divisor;
}
/*
* The exception filter saves the exception code and tests it
* against SIGFPE. If it tests true, the filter obtains the
* exception information, copies the exception record structure,
* and returns 1 to the dispatcher which then executes the handler.
* If the filter’s test of the code is false, the filter
* returns 0 to the handler, which continues its search for a
* handler in previous run-time frames. Eventually the last-chance
* handler executes. Note: Normally the filter printf is replaced
* with a call to a routine that logged the unexpected signal.
*/
except((code=exception_code()) == EXC_VALUE(EXC_SIGNAL,SIGFPE) ?
(except_info = exception_info(),
exception_record = *(except_info->ExceptionRecord), 1) :
(printf("unexpected signal exception code 0x%lx\n",
exception_code()), 0))
/*
* The exception handler follows and prints out the signal code,
* which has the following format:
*
* 0x 8 0ffe 0003
* | | | |
* hex SIGFPE EXC_OSF facility EXC_SIGNAL
*/
{ printf("Arithmetic error\n");
printf("exception_code() returns 0x%lx\n", code);
printf("EXC_VALUE macro in excpt.h generates 0x%lx\n",
EXC_VALUE(EXC_SIGNAL, SIGFPE));
printf("Signal code in the exception record is 0x%lx\n",
exception_record.ExceptionCode);
/*
* To find out what type of SIGFPE this is, look at the first
* optional parameter in the exception record. Verify that it is
* FPE_FLTDIV_TRAP).
*/
printf("No. of parameters is %lu\n",
exception_record.NumberParameters);
printf("SIGFPE type is 0x%lx\n",
exception_record.ExceptionInformation[0]);
/*
* Set return value to IEEE_PLUS_INFINITY and return.
*/
if (exception_record.ExceptionInformation[0] ==
FPE_FLTDIV_TRAP)
{
*((long*)&return_val) = IEEE_PLUS_INFINITY;
printf("Returning 0x%f to caller\n", return_val);
return 0;
}
/*
* If this is a different kind of SIGFPE, return gracelessly.
*/
else
return -1;
}
/*
* We get here only if no exception occurred in the try block.
*/
printf("okay: %f\n", quot);
exit(1);
}
#include <excpt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* main() sets up an exception handler to field the EXC_NOTWIDGET
* exception and then calls getwidgetbyname().
*/
void main(int argc, char *argv[])
{
char widget[20];
long code;
try {
if (argc > 1)
strcpy(widget, argv[1]);
else
{
printf("Enter widget name: ");
gets(widget);
}
getwidgetbyname(widget);
}
except((code=exception_code()) == EXC_NOTWIDGET)
{
printf("Exception 0x%lx: %s is not a widget\n",
code, widget);
exit(0);
}
}
/*
* getwidgetbyname() sets up an exception handler to field the
* EXC_NOTDECWIDGET exception. Depending upon the data it is
* passed, its try body calls exc_raise_status_exception() to
}
finally {
termination-handler
#include <stdio.h>
#include <signal.h>
#include <excpt.h>
#include <errno.h>
signed int
foo_except_filter(void)
{
printf("2. The exception causes the exception filter "
"to be evaluated.\n");
return 1;
}
Starting with DIGITAL UNIX Version 4.0, the interfaces flagged with an
asterisk (*) in the preceding list have new definitions that conform to POSIX
1003.1c. The old versions of these routines can be obtained by defining the
preprocessor symbol _POSIX_C_SOURCE with the value 199309L (which
denotes POSIX 1003.1b conformance — however, doing this will disable
POSIX 1003.1c threads). The new versions of the routines are the default
when compiling code under DIGITAL UNIX Version 4.0 or higher, but you
must be certain to include the header files specified on the reference pages
for the various routines.
For more information on programming with threads, see the Guide to the
POSIX Threads Library and cc(1), monitor(3), prof(1), and gprof(1).
Example 12–1 shows how to use thread-specific data in a function that can
be used by both single-threaded and multithreaded applications. For clarity,
most error checking has been left out of the example.
#include <stdlib.h>
#include <string.h>
#include <tis.h>
void _ _init_dirname()
{
tis_key_create(&key, free);
}
void _ _fini_dirname()
{
tis_key_delete(key);
}
{
char *dir, *lastslash;
/*
* Assume key was set and get thread-specific variable.
*/
dir = tis_getspecific(key);
if(!dir) { /* First time this thread got here. */
dir = malloc(PATH_MAX);
tis_setspecific(key, dir);
}
/*
* Copy dirname component of path into buffer and return.
*/
lastslash = strrchr(path, ’/’);
if(lastslash) {
memcpy(dir, path, lastslash-path);
dir[lastslash-dir+1] = ’\0’;
} else
strcpy(dir, path);
return dir;
}
tis_key_delete
Deletes a data key.
tis_getspecific
Obtains the data associated with the specified key.
tis_setspecific
Sets the data value associated with the specified key.
The _ _init_ and _ _fini_ routines are used in the example to initialize
and destroy the thread-specific data key. This operation is done only once,
and these routines provide a convenient way to ensure that this is the case,
even if the library is loaded with dlopen(). See ld(1) for an explanation of
how to use the _ _init_ and _ _fini_ routines.
The C and C++ compilers for Tru64 UNIX include the extended storage-class
attribute, _ _thread.
The _ _thread attribute must be used with the _ _declspec keyword to
declare a thread variable. For example, the following code declares an
integer thread local variable and initializes it with a value:
_ _declspec( _ _thread ) int tls_i = 1;
You must observe these guidelines and restrictions when declaring thread
local objects and variables:
• You can apply the _ _thread storage-class attribute only to data
declarations and definitions. It cannot be used on function declarations or
definitions. For example, the following code generates a compiler error:
#define Thread _ _declspec( _ _thread )
Thread void func(); // Error
• You can specify the _ _thread attribute only on data items with static
storage duration. This includes global data objects (both static and
extern), local static objects, and static data members of C++ classes.
You cannot declare automatic or register data objects with the _ _thread
attribute. For example, the following code generates compiler errors:
#define Thread _ _declspec( _ _thread )
void func1()
{
Thread int tls_i; // Error
}
• You must use the _ _thread attribute for the declaration and the
definition of a thread-local object, whether the declaration and definition
occur in the same file or separate files. For example, the following code
generates an error:
#define Thread _ _declspec( _ _thread )
extern int tls_i; // This generates an error, because the
int Thread tls_i; // declaration and the definition differ.
• You cannot use the _ _thread attribute as a type modifier. For example,
the following code generates a compile-time error:
char _ _declspec( _ _thread ) *ch; // Error
Note that a sizeof expression that includes the object being initialized
does not constitute a reference to itself and is allowed in C and C++.
/*
* NOTE: The putenv() function would have to set and clear the
* same mutex lock before it accessed the environment.
*/
longword
Ensures that naturally aligned data of four
bytes or greater can be accessed safely from
different threads sharing access to that data
in memory. Accessing data items of three
bytes or less and unaligned data may result
in data items written from multiple threads
being inconsistently updated.
quadword
Ensures that naturally aligned data of eight
bytes can be accessed safely from different
threads sharing data in memory. Accessing
data items of seven bytes or less and unaligned
data may result in data items written from
multiple threads being inconsistently updated.
This is the default.
1. The thread spins for a number of iterations waiting for the event to
occur.
2. It yields the processor to other threads a number of times, checking for
the event to occur.
3. It posts a request to be awakened and goes to sleep.
When another thread causes the event to occur, it will awaken the sleeping
thread.
You may get better performance by tuning the threaded environment with
the MP_SPIN_COUNT and MP_YIELD_COUNT environment variables or by
using the mpc_destroy routine:
• MP_SPIN_COUNT — If your application is running standalone, the default
settings will give good performance. However, if your application needs
to share the processors with other applications, it is probably appropriate
to reduce MP_SPIN_COUNT. This will make the threads waste less time
spinning and give up the processor sooner; the cost is the extra time to
put a thread to sleep and re-awaken it. In such a shared environment,
an MP_SPIN_COUNT of about 1000 might be a good choice.
• mpc_destroy — If you need to perform operations that are awkward
when extra threads are present (for example, fork), the mpc_destroy
routine can be useful. It destroys any worker threads created to run
parallel regions. Normally, you would only call it when you are not inside
a parallel region. (The mpc_destroy routine is defined in the libots3
library.)
13.4.1 Scoping
The OpenMP parallel construct applies to the structured block that
immediately follows it. When more than one statement is to be performed
in parallel, make sure that the structured block is contained within curly
braces. For example:
#pragma omp parallel
{
pstatement one
pstatement two
}
The preceding structured block is quite different from the following, where
the OpenMP parallel construct applies to only the first statement:
#pragma omp parallel
pstatement one
pstatement two
The use of curly braces to explicitly define the scope of the subsequent block
(or blocks) is strongly encouraged.
13.4.2 Deadlock
As with any multithreaded application, programmers must use care to
prevent run-time deadlock conditions. With the implicit barriers at the end
of many OpenMP constructs, an application will result in a deadlock if all
threads do not actively participate in the construct. These types of conditions
may be more prevalent when implementing parallelism in dynamic extents
of the application. For example:
worker ()
{
#pragma omp barrier
}
main ()
{
#pragma omp parallel sections
{
#pragma omp section
worker();
}
}
The preceding example results in deadlock (with more than one thread
active) because not all threads visit the worker routine and the barrier
waits for all threads. The -check_omp option (see Section 13.1) aids in
detecting such conditions.
1. The lock to be associated with the lock variable must first be initialized.
2. The associated lock is made available to the executing thread.
3. The executing thread is released from lock ownership.
4. When finished, the lock must always be disassociated from the lock
variable.
Attempting to use the locks outside the above sequence may cause
unexpected behavior, including deadlock conditions.
Default value for The default value is 0. This implementation does not
OMP_DYNAMIC
support dynamic adjustments to the thread count.
Default schedule When a for or parallel for loop does not contain a
schedule clause, a dynamic schedule type is used
with the chunksize set to 1.
13.6 Debugging
The following sections provide tips and hints on how to diagnose the behavior
of and debug applications that use the OpenMP application programming
interface (API).
Using the dis command to disassemble the object module produced from the
preceding source code results in the following output:
_ _main_6: 1
0x0: 27bb0001 ldah gp, 1(t12)
0x4: 2ffe0000 ldq_u zero, 0(sp)
0x8: 23bd8110 lda gp, -32496(gp)
0xc: 2ffe0000 ldq_u zero, 0(sp)
0x10: 23defff0 lda sp, -16(sp)
0x14: b75e0000 stq ra, 0(sp)
0x18: a2310020 ldl a1, 32(a1)
0x1c: f620000e bne a1, 0x58
0x20: a77d8038 ldq t12, -32712(gp)
0x24: 6b5b4000 jsr ra, (t12), omp_get_thread_num
0x28: 27ba0001 ldah gp, 1(ra)
0x2c: 47e00411 bis zero, v0, a1
0x30: 23bd80e8 lda gp, -32536(gp)
0x34: a77d8028 ldq t12, -32728(gp)
0x38: a61d8030 ldq a0, -32720(gp)
0x3c: 6b5b4000 jsr ra, (t12), printf
0x40: 27ba0001 ldah gp, 1(ra)
0x44: 23bd80d0 lda gp, -32560(gp)
0x48: a75e0000 ldq ra, 0(sp)
0x4c: 63ff0000 trapb 0x50: 23de0010 lda sp, 16(sp)
0x54: 6bfa8001 ret zero, (ra), 1
0x58: 221ffff4 lda a0, -12(zero)
0x5c: 000000aa call_pal gentrap
0x60: c3ffffef br zero, 0x20
0x64: 2ffe0000 ldq_u zero, 0(sp)
0x68: 2ffe0000 ldq_u zero, 0(sp)
0x6c: 2ffe0000 ldq_u zero, 0(sp)
main:
0x70: 27bb0001 ldah gp, 1(t12)
0x74: 2ffe0000 ldq_u zero, 0(sp)
0x78: 23bd80a0 lda gp, -32608(gp)
0x7c: 2ffe0000 ldq_u zero, 0(sp)
0x80: a77d8020 ldq t12, -32736(gp)
0x84: 23defff0 lda sp, -16(sp)
0x88: b75e0000 stq ra, 0(sp)
0x8c: 47e05410 bis zero, 0x2, a0
0x90: 6b5b4000 jsr ra, (t12), omp_set_num_threads
0x94: 27ba0001 ldah gp, 1(ra)
0x98: 47fe0411 bis zero, sp, a1
0x9c: 2ffe0000 ldq_u zero, 0(sp)
_ _original-rou-
tine-name_listing-line-number
2 The call to _OtsEnterParallelOpenMP is inserted by the compiler to
coordinate the thread creation and execution for the parallel region.
Run-time control remains within _OtsEnterParallelOpenMP until
all threads have completed the parallel region.
13.6.2.1 Ladebug
This section describes how to use the Ladebug debugger with OpenMP
applications. It explains unique considerations for an OpenMP application
over a traditional, multithreaded application. It uses the example program
in Section 13.6.1 to demonstrate the concepts of debugging an OpenMP
application. For more complete information on debugging multithreaded
programs, see the Ladebug Debugger Manual.
Because OpenMP applications are multithreaded, they can generally be
debugged using the same strategies as regular multithreaded programs.
There are, however, a few special considerations:
• As with optimized code, the compiler alters the source module to enable
OpenMP support. Thus, the source module shown in the debugger
will not reflect the actual execution of the program. For example, the
generated routines from the outlining process performed by the compiler
will not be visible as distinct routines. Prior to a debugging session, an
output listing or object module disassembly will provide the names of
You can modify the number of active threads in a program by calling either
omp_set_num_threads or mpc_destroy. In either case, any data declared
threadprivate and associated with the slave threads is reinitialized to the
values at application startup. For example, if the active number of threads
is 4 and a call is made to set the number to 2 (via omp_set_num_threads),
then any threadprivate data associated with OpenMP threads 1, 2, and 3
will be reset. The threadprivate data associated with the master thread
(OpenMP thread 0) is unchanged.
Event Subscribers
EVM Daemon
Event Posters
ZK-1458U-AI
1. Templates are created for all events that some process may want to
post, and these templates are stored in an EVM database when the
product or subsystem is installed.
The event name data item is a character string that identifies an event,
generally indicating the origin of the event and what happened. An event
name uniquely identifies a particular type of event, and you want different
instances of the same event to have the same name.
EVM uses the event name to decide if a user is authorized to post or access
a particular event and to find template information for the event. Client
applications can use event names in conjunction with an event filter (see
Section 14.7.10) to select the events that they want to receive and to decide
on any action that they need to take when an event arrives. The system
administrator can use event names to search the event logs for events that
are of particular interest.
An event name has the following characteristics:
• A name is series of one or more components, which are separated by dots.
• A component is made up of one or more letters, digits and underscore
characters, in any order.
• There is no upper limit to the number of components in a name.
• A name cannot begin or end with a dot.
After you have chosen and published an event name, avoid changing
it because the events that an application posts are part of its external
interface, and other applications or product components might depend upon
receiving them.
The previous section stated that the more detail that you included in an
event name, the easier it is for an administrator to use an EVM filter to
search the event logs for events that are interesting. For example, the
event sys.unix.hw.registered.cpu reports that the operating system’s
hardware management subsystem has detected and registered a processor.
The event contains the hardware ID of the processor in a variable data item
(see Section 14.5.2), and you can see the hardware ID if you display the
event with the event viewer or evmshow. If you are tracing a problem that
is related to that processor, you might want to use an event filter to select
In the example, the asterisk (*) wildcard character ensures that you find
all events posted by the hardware subsystem that include the identifier
2, regardless of what they are reporting. However, this filter might not
select all of the events for the device that interests you because subsystems
other than the hardware subsystem might also report information about
the processor, and you want to include those events in the search. You can
increase the scope of the search by specifying [name *.2], but other events
in the log with the number 2 in their names that have nothing to do with
hardware IDs would be included in the results.
The convention of reserved component names makes it possible to select
related events, regardless of which subsystem or application posts them. By
convention, a reserved component name begins with an underscore character
(_) and always identifies a particular type of entity. The posting subsystem
or application appends the reserved component name to the base event name
before posting the event, and, depending on the entity being identified, the
following component might then identify the specific instance.
Although reserved component names are generally defined on behalf of a
particular subsystem or application, after a name has been defined, its use is
not restricted — anything that has information to report about the entity can
include the reserved name and entity identifier in the events that it posts.
For example, the reserved component name _hwid specifies a hardware
device identifier, as defined by the hardware management subsystem, and
must be followed by the device-id. So, continuing the previous example,
the name of the event that reports the registration of the processor is
sys.unix.hw.registered.cpu._hwid.2. You can find all events that
relate to all hardware devices with the following command:
evmget -A -f "[name *._hwid]"
You can then narrow the search to the processor that most interests you
with the following command:
evmget -A -f "[name *._hwid.2]"
The use of the wildcard in the filter for all components except the hardware
ID components ensures that the search yields all related events, regardless
of which subsystem or application posted them, provided that those posters
followed the convention.
Use EVM’s API functions to compare the name of an event with the name
you are looking for. Do not use strcmp( ); the name of the incoming event
You can escape the special meaning of $ and @ characters in the format
text by preceding them with a backslash (\). To include a literal backslash
in the text, use a double backslash (\\). To separate the name of the data
item or variable from adjacent text, you can surround the name in braces,
for example, ${app}.
Table 14–2 shows some examples of the way that variables and data items
are substituted into an event’s format text to produce a formatted version
of the event.
The priority of an event is used as the basis for event selection to log, sort,
review, and take action — human or automated. The priority is not used to
establish the order in which events will be delivered to subscribing EVM
clients; events are delivered in the order in which they are received by the
EVM daemon. The priority is an integer value in the range 0-700, with 0
being the least significant priority. See EvmEvent(5) for information about
the various priority levels.
You can expect that system administrators will respond to event priorities
in the following ways:
• Configure the logger to log all events with priority 200 (notice level) or
higher.
• Configure the logger to send mail or issue an alert (for example, page
someone) when an event of priority 600 (alert level) or higher is posted.
• Use the viewer to search for all events with priority 300 (warning level)
or higher.
• Use the viewer to peruse logged events of all priorities to help analyze
problems or to verify that the system is operating correctly.
14.5.1.4 I18N Catalog Name, Message Set ID, and Message ID Data Items
The reference data item is used to find the event explanation text for a
detailed display of the event. The value of this item is passed to the event
channel’s explain script, along with the name of the event, to allow it to
identify the explanation text associated with the event. Because each
channel can have its own explain script, the format of the field might be
different for each channel — however, for events that are stored in and
retrieved from the EVM log (the evmlog channel), this item should contain a
string of the following form:
cat:catalog_name[:set_number]
1. Decide on a family name for a set of related events. (See Section 14.5.1.1
for details.)
2. Create a list of the status changes that might be of interest to a
monitoring entity, and choose a name for each event. (See Section 14.6.1
for details.)
3. Decide on the contents of each event. All events need a name. Most
events need a format string and a priority, and many also need
variables. For each variable, consider the type and possible values. (See
Section 14.5 for details.)
4. Write a detailed description of each event for documentation purposes.
Include details on what the event means, when it might occur, any
actions the user or responsible subscriber should take in response to it,
and the contents of the event (particularly any variable data items). The
explanation text is usually held in a catalog file and can be accessed for
display. (See Section 14.6.2 for details.)
5. For each event, decide which items go into the template and which
will be coded by the poster. Except for the event name, all items in
both posting code and templates are optional. If an optional item is
declared in both places, the poster’s declaration has precedence. (See
Section 14.6.3 for details on templates, Section 14.5 for details on event
items that are commonly posted, and Section 14.6.3.3 for details on how
data items in templates and posted events are merged.)
6. Decide whether the events should be internationalized. If so, choose a
name for the I18N catalog file and establish any required message sets
within the catalog. (See Section 14.6.4 for details.)
Example 1:
EVENT sys.unix.evm.daemon.event_activity
Explanation:
Note: You can change the parameters that control the posting
of this event by modifying the daemon configuration file,
/etc/evmdaemon.conf.
Deciding which items should be supplied by event posters and which should
be supplied in the template is a design-level decision. As a general rule, it
is better to include constant data items in the event template than to have
them hardcoded into an event by posting programs.
A key benefit of the event template mechanism is that it allows you to
centralize the fixed attributes of all of your application’s events, making
it very easy to change them during the development cycle and providing
a single place to look for the information after the application has been
deployed.
As a general rule, try to minimize the amount of event information that you
hardcode into a posting application program and to put as much as possible
into the event template. Typically, your application should only provide:
• Event name (required — it must have at least three components and be
at least as long as the event name in the matching template)
• Contents of any variables
The template should generally include:
• Event name (required — it must have at least two components)
You can include as many variables as you like in an event, but note that
opaque variables (binary structures) are not supported in templates.
14.6.3.2 Matching the Names of Posted Events with Event Template Names
Each time an attempt is made to post an event, EVM looks in its template
database for the template whose event name matches the name of the posted
event. If no match is found, EVM returns an error code to the program that
posted the event. If a match is found, EVM then retrieves any data items
held in the template and combines them with the items supplied by the
program that posted the event. This operation produces the merged event
that is distributed to subscribers. See Section 14.6.3.3 for details on the
merging operation.
The template-matching process requires a match only between the leftmost
components of a posted event’s name and all of the components of a template
event’s name. EVM looks for the best match in its database, using the
following rules:
After the EVM daemon has successfully validated a posted event, it merges
the data items contained in the posted event with any data items contained
in the template, and then distributes the merged event to any clients that
have subscribed to the event. The merge process gives the event designer
maximum flexibility in deciding which text and data items are to be provided
by the template and which are to be provided by the poster.
Figure 14–2 illustrates the concept of event merging.
ZK-1399U-AI
If the same data item is supplied in both the template and the posted event,
the posted value is used in the merged event.
The merge process yields a canonical (binary) event structure that contains
a combination of the data items from the posted event and the template.
The merged event is distributed to subscribers in its canonical form, not as
a formatted message, and subscribers must use the EVM API functions
to format the event for display or to extract information from it. The API
functions are described in Section 14.7.
You can check whether your templates are registered by using evmwatch
with the -i option. For example, the following command lists the names of
all event templates registered for the myapp application:
evmwatch -i -f "[name myco.myprod.myapp]" | evmshow -t "@name"
Use the -d option of evmshow to display the template details. Note that
evmwatch will not return the templates of any events for which you do not
have access authorization, so you may need to be logged in as root to see
your templates.
All message identifiers for the event must relate to the same message
catalog, and they must all belong to the same message set (1, by default).
In general, the catalog ID, set ID, and message ID for the event format
string should all be supplied in the event template because the format string
is usually fixed. Where events contain string-type variables, the variables
are likely to refer to items such as device names or application names, which
usually will not need to be translated, regardless of the language for display
— and hence in most cases it will not be necessary to supply a message ID.
In the rare cases in which the value of a string variable does need to be
translated, the poster must supply the message ID.
Table 14–5 shows some internationalized values for an example event.
See the Writing Software for the International Market manual for additional
information on I18N issues.
1. If possible, restrict the use of any entity returned by any API function to
the thread in which it was established. These items include:
If you do not follow these rules, it is highly likely that random errors will
occur.
In this case, you must not destroy the event in the callback function, because
the assignment copies just the reference to the event, not the event body.
You must still arrange to destroy the event from elsewhere after you have
finished with it; otherwise, you may have introduced a memory leak.
See Section 14.7.6 for a description of event assignment.
All EVM clients need to work with the EVM event, an opaque binary
structure that can hold standard data items and variables. Example 14–2
shows you how to create an event, add items to it, and then retrieve the
items from it.
The example introduces the following functions:
• EvmEventCreate — Creates an empty event. (See EvmEventCreate(3)
for details.)
• EvmEventDestroy — Destroys a previously created event, freeing its
memory. This function must be used if it is necessary to free an event.
Although the event reference points to a structure allocated from the
heap, that structure contains references to other structures, and hence
using free() directly on the event reference will result in lost memory.
(See EvmEventDestroy(3) for details.)
• EvmItemSet — Sets data item values in the event. The list of
items and variables to be supplied is the same as that supplied for
EvmEventCreateVa. (See EvmItemSet(3) for details.)
• EvmItemGet — Supplies the value of a specified event data item. (See
EvmItemGet(3) for details.)
• EvmItemRelease — Releases any memory that was allocated when a
specified data item was retrieved from an event by EvmItemGet(). (See
EvmItemRelease(3) for details.)
#include <stdio.h>
#include <evm/evm.h>
main()
{
EvmEvent_t event;
EvmItemValue_t itemval;
EvmStatus_t status;
EvmEventCreate(&event); 1
EvmItemSet(event,EvmITEM_NAME,"myco.examples.app.started"); 2
EvmItemSet(event,EvmITEM_PRIORITY,200);
status = EvmItemGet(event,EvmITEM_NAME,&itemval); 3
if (status == EvmERROR_NONE)
{ fprintf(stdout,"Event name: %s\n",itemval.NAME);
EvmItemRelease(EvmITEM_NAME,itemval);
}
EvmEventDestroy(event); 4
}
You can reduce the size and improve the efficiency of your code by creating
an event and adding items to it in a single step, using the varargs
(variable-length argument list) version of the create function — and you can
add items to an existing event efficiently by using the varargs version of
the item-set function.
Example 14–3 introduces the following functions:
#include <stdio.h>
#include <evm/evm.h>
main()
{
EvmEvent_t event;
EvmEventCreateVa(&event, 1
EvmITEM_NAME,"myco.examples.app.started",
EvmITEM_PRIORITY,200,
EvmITEM_NONE);
EvmItemSetVa(event,
EvmITEM_NAME,"myco.examples.app.finished", 2
EvmITEM_PRIORITY,100,
EvmITEM_NONE);
EvmItemSetVa(event,
EvmITEM_VAR_UINT16,"exit_code",17, 3
EvmITEM_VAR_STRING,"progname","my_app",
EvmITEM_NONE);
EvmEventDump(event,stdout); 4
EvmEventDestroy(event); 5
}
#include <stdio.h>
#include <evm/evm.h>
void main()
{
EvmEvent_t event;
EvmStatus_t status;
EvmVarValue_t varval_1, varval_2; 1
EvmVarStruct_t varinfo;
EvmString_t progname;
EvmUint16_t exit_code;
EvmEventCreateVa(&event,
EvmITEM_NAME,"myco.examples.app.finished",
EvmITEM_NONE);
/*
* Set and retrieve some values using basic set/get functions:
*/
varval_1.STRING = "my_app";
varval_2.UINT16 = 17;
EvmVarSet(event,"progname",EvmTYPE_STRING,varval_1,0,0); 2
EvmVarSet(event,"exit_code",EvmTYPE_UINT16,varval_2,0,0);
status = EvmVarGet(event,"progname",&varinfo); 3
if (status == EvmERROR_NONE)
{ fprintf(stdout,"Program name: %s\n",varinfo.value.STRING);
EvmVarRelease(&varinfo);
}
status = EvmVarGet(event,"exit_code",&varinfo);
if (status == EvmERROR_NONE)
{ fprintf(stdout,"Exit code: %d\n",varinfo.value.UINT16);
EvmVarRelease(&varinfo);
}
/*
* Set and retrieve the same values using convenience functions:
*/
EvmVarSetString(event,"progname","my_app"); 4
EvmVarSetUint16(event,"exit_code",17);
status = EvmVarGetString(event,"progname",&progname,NULL); 5
if (status == EvmERROR_NONE)
fprintf(stdout,"Program name: %s\n",progname);
free(progname); 6
status = EvmVarGetUint16(event,"exit_code",&exit_code);
if (status == EvmERROR_NONE)
fprintf(stdout,"Exit code: %d\n",exit_code);
EvmEventDestroy(event); 7
}
1 To add a variable to the event, you must first place the value in a union
of type EvmVarValue_t. The members of the union have the same
names as the EVM variable types.
2 Use EvmVarSet( ) to add the variables to the event, giving them
meaningful names. The final two arguments are set to 0 unless you
are adding an opaque variable or supplying an I18N message ID for a
string variable.
3 You can retrieve the value of any variable by passing its name to
EvmVarGet( ), which copies the value into an EvmVarStruct_t
structure. The structure also contains the name, type, and size of the
variable, so you can write generic code to handle any type of variable.
Retrieving a variable does not remove the variable from the event,
The most likely reason for creating an event is to post it. Posting an event
results in the event being distributed to subscribers by the EVM daemon.
Before you can post the event, you must create a posting connection to the
daemon.
Example 14–5 shows how to create the connection, post the event, and
disconnect.
The example introduces the following functions:
• EvmConnCreate — Establishes a connection between an application
program and EVM, and defines how I/O activity is to be handled. A
separate connection must be established for each type of connection:
posting, listening (subscribing), or service. (See EvmConnection(5) and
EvmConnCreate(3) for details.)
• EvmEventPost — Posts an event to EVM. (See EvmEventPost(3) for
details.)
• EvmConnDestroy — Destroys a specified connection. (See
EvmConnDestroy(3) for details.)
#include <stdio.h>
#include <evm/evm.h>
void main()
{ EvmEvent_t event;
EvmStatus_t status;
EvmConnection_t conn;
EvmEventCreateVa(&event, 2
EvmITEM_NAME,"myco.examples.app.error_detected",
EvmITEM_NONE);
status = EvmEventPost(conn,event);
if (status != EvmERROR_NONE)
{ fprintf(stderr,"Failed to post event\n");
exit(1);
}
EvmEventDestroy(event); 3
EvmConnDestroy(conn);
}
You will need to use the EVM read and write functions if you are writing a
program that performs any of the following operations:
• Stores events in a file
• Passes events to another process through a pipe or socket connection
• Analyzes events stored in a file
• Receives events from a process other than the EVM daemon
You cannot write events directly using the standard UNIX write functions
because the event handle only contains a pointer to the body of the event
— and because the location of the body may change each time the event is
modified. Conversely, when you read an event, it is not enough just to read
the body; a handle has to be created to allow you to reference the event
through the API functions.
Example 14–6 shows you how to write events to a file, to read them from a
file into your program, and to validate them.
The example introduces the following functions:
• EvmEventWrite — Writes an event to an open file descriptor. (See
EvmEventWrite(3) for details.)
• EvmEventRead — Creates a new event structure and populates it with
an event read from a file descriptor. EvmEventDestroy( ) must be used
to free the new event. (See EvmEventRead(3) for details.)
• EvmEventValidate — Performs a data integrity check on the event.
This check is intended to validate an event that has just been received
#include <stdio.h>
#include <fcntl.h>
#include <evm/evm.h>
void main()
{ EvmEvent_t event_in,event_out;
EvmStatus_t status;
EvmItemValue_t itemval;
int fd;
EvmEventCreateVa(&event_out, 1
EvmITEM_NAME,"myco.examples.app.saved_event",
EvmITEM_NONE);
fd = open("eventlog",O_RDWR | O_CREAT | O_TRUNC, 2
S_IRUSR | S_IWUSR);
if (fd < 0)
{ fprintf(stderr,"Failed to open output log file\n");
exit(1);
}
status = EvmEventWrite(fd,event_out);
if (status != EvmERROR_NONE)
{ fprintf(stderr,"Failed to write event to log file\n");
exit(1);
}
lseek(fd,0,SEEK_SET); 3
status = EvmEventRead(fd,&event_in);
if (status != EvmERROR_NONE)
{ fprintf(stderr,"Failed to read event from log file\n");
exit(1);
}
status = EvmEventValidate(event_in); 4
if (status != EvmERROR_NONE)
{ fprintf(stderr,"Event read from logfile is invalid");
exit(1);
}
status = EvmItemGet(event_in,EvmITEM_NAME,&*itemval); 5
if(status == EvmERROR_NONE)
{ fprintf(stdout,"Event name: %s\n",itemval.NAME);
EvmItemRelease(EvmITEM_NAME,itemval);
}
EvmEventDestroy(event_in); 6
EvmEventDestroy(event_out);
}
A program that subscribes for receiving event notifications must perform the
following operations:
• Create a listening connection to the EVM daemon
• Tell the daemon which events it is interested in by passing a filter string
• Monitor event activity on the connection and be prepared to handle each
event as it arrives
Example 14–7 waits for events to arrive and displays each incoming event
on stdout.
The example introduces the following functions:
• EvmConnSubscribe — Requests notification of any posted events that
match the supplied filter. (See EvmConnSubscribe(3) for details.)
• EvmConnWait — Blocks until activity is detected on a specified
connection. When activity is detected, the calling program can call
EvmConnDispatch( ) to handle the activity. (See EvmConnWait(3) for
details.)
• EvmConnDispatch — Handles any outstanding I/O on a specified
connection by calling the program’s callback function as needed. (See
EvmConnDispatch(3) for details.)
• EvmEventFormat — Formats an event. (See EvmEventFormat(3) for
details.)
#include <stdio.h>
#include <evm/evm.h>
/*====================================================
* Function: main()
*====================================================*/
main()
{ EvmConnection_t conn;
EvmStatus_t status;
switch (cbdata->reason) { 5
case EvmREASON_EVENT_DELIVERED:
EvmEventFormat(buff, sizeof(buff), cbdata->event);
fprintf(stdout,"Event: %s\n",buff);
EvmEventDestroy(cbdata->event); 6
break;
default: 7
break;
}
}
If you are writing a program that has responsibilities other than just
listening for events, you may not want to use EvmEventWait( ) to wait for
events to arrive. For example, you may wish to use the select system
call to wait for I/O activity on multiple file descriptors, including the EVM
connection.
#include <stdio.h>
#include <sys/time.h>
#include <evm/evm.h>
void HandleInput();
void EventCB(EvmConnection_t conn, EvmCallbackArg_t cbarg,
EvmCallbackData_t *cbdata);
/*===============================================
* Function: main()
*===============================================*/
main()
{ EvmConnection_t conn;
EvmStatus_t status;
fd_set read_fds;
int conn_fd;
EvmBoolean_t io_waiting;
EvmConnFdGet(conn,&conn_fd); 1
for (;;) 2
{ FD_ZERO(&read_fds);
FD_SET(fileno(stdin),&read_fds);
FD_SET(conn_fd,&read_fds);
select(FD_SETSIZE,&read_fds,NULL,NULL,NULL);
if (FD_ISSET(fileno(stdin),&read_fds))
HandleInput();
status = EvmConnCheck(conn,&io_waiting); 3
if (status != EvmERROR_NONE)
{ fprintf(stderr,"Connection error\n");
exit(1);
}
if (io_waiting)
{ status = EvmConnDispatch(conn);
if (status != EvmERROR_NONE)
{ fprintf(stderr,"Connection dispatch error\n");
exit(1);
}
}
}
}
/*===============================================
* Function: HandleInput()
*===============================================*/
void HandleInput() 4
{ char buff[256];
if (feof(stdin))
exit(0);
if (fgets(buff,sizeof(buff),stdin) == NULL)
exit(0);
if (buff[0] == ’\n’)
exit(0);
fprintf(stdout,buff);
}
/*===============================================
* Function: EventCB()
*===============================================*/
switch (cbdata->reason) {
case EvmREASON_EVENT_DELIVERED:
EvmEventDestroy(cbdata->event);
break;
default:
break;
}
}
#include <stdio.h>
#include <sys/time.h>
#include <evm/evm.h>
/*===============================================
* Function: main()
*===============================================*/
main()
{ EvmConnection_t conn;
Evmstatus_t status;
int conn_fd;
char *filter_string;
status = EvmConnSubscribe(conn,NULL,filter_string); 3
if (status != EvmERROR_NONE)
{ fprintf(stderr,"Failed to subscribe for event notification\n");
exit(1);
}
free(filter_string);
for (;;) 4
{ status = EvmConnWait(conn,NULL);
if (status != EvmERROR_NONE)
{ fprintf(stderr,"Connection error\n");
exit(1);
}
if (EvmConnDispatch(conn) != EvmERROR_NONE)
{ fprintf(stderr,"Connection dispatch error\n");
exit(1);
}
}
}
/*===============================================
* Function: EventCB()
*===============================================*/
void EventCB(EvmConnection_t conn, EvmCallbackArg_t cbarg,
EvmCallbackData_t *cbdata)
{ EvmBoolean_t match;
if (! filters_initialized)
{ if (EvmFilterCreate(&f1) != EvmERROR_NONE)
{ fprintf(stderr,"Failed to create filter evaluator\n");
exit(1);
}
if (EvmFilterSet(f1,FILTER_1) != EvmERROR_NONE)
{ fprintf(stderr,"Failed to set filter evaluator\n");
exit(1);
}
EvmFilterCreate(&f2);
EvmFilterSet(f2,FILTER_2);
EvmFilterCreate(&f3);
EvmFilterSet(f3,FILTER_3);
filters_initialized = EvmTRUE;
}
switch (cbdata->reason) { 6
case EvmREASON_EVENT_DELIVERED:
EvmFilterTest(f1,cbdata->event,&match);
if (match)
fprintf(stdout,"Filter 1 event received\n");
EvmFilterTest(f2,cbdata->event,&match);
if (match)
fprintf(stdout,"Filter 2 event received\n");
EvmFilterTest(f3,cbdata->event,&match);
if (match)
fprintf(stdout,"Filter 3 event received\n");
EvmEventDestroy(cbdata->event);
break;
default:
break;
}
}
1 This section of code defines three simple filter strings. The first two
filter by name alone, but the third string selects events with either of
two names, provided they have a priority of at least 300.
2 This section of code combines the three filter strings into a single
logical expression, surrounding each substring with parentheses and
separating them with the logical OR operator. This will cause the
daemon to notify you of any event that matches at least one of the
substrings.
The EVM naming policy allows an event name to be extended with any
number of trailing components, yet still match its base name. This means
that you cannot depend on an event having exactly the name you expect it to
have because it may have extra trailing components.
Therefore, when you need to compare an event’s name against a known
name, do not use the usual string comparison functions because they will
incorrectly fail to match the name if components have been added. Instead,
you should use EVM’s name-matching functions. These functions match an
event name against the pattern you supply, ignoring any trailing components
in the candidate name. They also allow you to include wildcard characters
in your name pattern.
Example 14–10 introduces the following function:
• EvmEventNameMatch — Takes the following input arguments: an event
name string (which may contain wildcard characters) and an event.
Returns an indication of whether the event matches the name string.
The following function is related to EvmEventNameMatch:
• EvmEventNameMatchStr — Takes an event name in a character string,
rather than extracting it from an event.
#include <stdio.h>
#include <evm/evm.h>
/*===============================================
* Function: main()
*===============================================*/
main()
{ EvmStatus_t status;
EvmEvent_t event;
EvmBoolean_t match;
char buff[80];
1 This section of code reads events from stdin and displays only
those events that match the wildcard string *.msg. This match
will work even though events of this type usually have the name
sys.unix.evm.msg.user or sys.unix.evm.msg.admin.
#include <stdio.h>
#include <evm/evm.h>
/*===============================================
* Function: main()
*===============================================*/
main()
{ EvmConnection_t conn;
EvmStatus_t status;
int conn_fd;
for (;;)
{ status = EvmConnWait(conn,NULL);
if (status != EvmERROR_NONE)
{ fprintf(stderr,"Connection error\n");
exit(1);
}
if (EvmConnDispatch(conn) != EvmERROR_NONE)
{ fprintf(stderr,"Connection dispatch error\n");
exit(1);
}
}
}
/*===============================================
* Function: EventCB()
*===============================================*/
void
EventCB(EvmConnection_t conn, EvmCallbackArg_t cbarg,
EvmCallbackData_t *cbdata)
{ char buff[256];
switch (cbdata->reason) {
case EvmREASON_EVENT_DELIVERED:
EvmEventFormat(buff, sizeof(buff), cbdata->event);
fprintf(stdout,"Event: %s\n",buff);
EvmEventDestroy(cbdata->event);
sleep(1); 3
break;
case EvmREASON_EVENTS_MISSED: 4
fprintf(stdout,"*** Missed %d incoming events\n",
cbdata->extension.eventMissedData.missedCount);
break;
default:
break;
}
}
An event channel may be an active channel, in which case it posts its own
event information to EVM as soon as the event occurs, or it may be a passive
channel, meaning that the information may accumulate within the channel
but EVM has to take the action to look for it.
An event channel does not have to be a formal event notification mechanism.
It can be anything that is capable of storing information or showing a status
or a change of state. For example:
• If an application or system components writes state information to its
own log file, each line in the log file can be thought of as an event. The
log file can be checked periodically for new lines, and an event can be
posted for each new line found. The log file itself also serves as a place
from which to retrieve historical events.
• Some applications and system components provide a means of querying
status. In these cases, the status can be monitored periodically, and an
event can be posted whenever a significant change is detected. Because
this type of event channel typically does not include a means of storing
event information, EVM’s own logging mechanism can be used to log
the events.
• If a central part of an application handles all event information for the
application, it may be feasible to modify the handling code so that it also
forwards event information to EVM. This is an example of an active
event channel.
The process of taking an existing event channel and making it accessible
through EVM is termed encapsulation.
1. Use standard UNIX tools such as grep, awk, and sed to select the
event lines, removing blank lines and comments, and reformat them as
necessary for the next step. This should be a reasonably simple matter
if the events are single lines of text, with a constant format in each line,
and include items such as a timestamp, host name, and message in
the same position in every line.
2. Convert the lines into EVM events. You may be able to do this by using
UNIX tools to format the lines into a form suitable for input to evmpost,
using the -r option to produce EVM events on stdout instead of
posting them. Alternatively, for a faster conversion, you can use the
EVM channel utility /usr/share/evm/channels/bin/text2evm to
do the conversion. This tool currently requires input of the form:
evm-event-name date time host user message
where:
• evm-event-name is the NAME of the EVM event that will be
produced by the tool. The first few components of the names of all
events passed through a particular channel should be the same, so
that the events can be associated with the channel.
• date and time make up the TIMESTAMP item for the event. The
components of the date must be in the basic format year/month/day,
where the / characters can be replaced by any of the following
characters:
- : .
There is also some flexibility in the format of the values to allow for
the variations in logfile formats and to minimize the amount of
conversion work that may need to be done in a shell script:
– The year can be two or four digits, or can be replaced with
the ? character. If four digits are supplied, the year is taken
If your channel’s log files are difficult to convert to EVM format — for
example, because each entry is made up of multiple unstructured lines of
text, which cannot be parsed easily — it may be better not to supply a get
function, but instead to allow the events to be logged by the EVM logger as
they are posted. This consumes more storage space, as the events would be
stored in two places, but it may significantly improve retrieval time and
programming effort.
If you supply your own get function for the channel, be sure to change the
filter strings in the EVM logger’s configuration file so that your events are
The explain function is invoked with the name of the event requiring
explanation and an optional reference value. If supplied, the reference is
the contents of the event’s reference data item. If no reference is available,
evmshow passes a hyphen for this argument, but the function should also
allow the argument to be omitted.
EVENT_NAME=myco.admin.mylog.line_added
# Find out how many lines there were in the file last time
# we checked:
OLDCOUNT=‘cat $STATE‘
The size of the default pointer type on Tru64 UNIX systems is 64 bits, and all
system interfaces use 64-bit pointers. The Compaq C compiler, in addition to
supporting 64-bit pointers, also supports the use of 32-bit pointers.
In most cases, 64-bit pointers do not cause any problems in a program
and the issue of 32-bit pointers can be ignored altogether. However, in the
following cases, the issue of 32-bit pointers does become a concern:
• If you are porting a program with pointer-to-int assignments
• If the 64-bit pointer size is unnecessary for your program and it causes
your program to use too much memory — for example, your program
uses very large structures composed of pointer fields and has no need to
exceed the 32-bit address range in those fields
• If you are developing a program for a mixed system environment (32- and
64-bit systems) and the program’s in-memory structures are accessed
from both types of systems
The use of 32-bit pointers in applications requires that the applications be
compiled and linked with special options and, depending on the specific
nature of the code, may also require source-code changes.
The following types of pointers are referred to in this appendix:
• Short pointer: A 32-bit pointer. When a short pointer is declared, 32
bits are allocated.
• Long pointer: A 64-bit pointer. When a long pointer is declared, 64 bits
are allocated. This is the default pointer type on Tru64 UNIX systems.
• Simple pointer: A pointer to a nonpointer data type, for example, int
*num_val. More specifically, the pointed-to type contains no pointers, so
the size of the pointed-to type does not depend on the size of a pointer.
• Compound pointer: A pointer to a data type whose size depends upon the
size of a pointer, for example, char **FontList.
When compiled with either the default settings or the −xtaso option, the
sample program prints the following message:
A pointer is 8 bytes
When compiled with the −xtaso_short option, this sample program prints
the following message:
A pointer is 4 bytes
The -taso option ensures that the text and data segments of an application
are loaded into memory that can be reached by a 31-bit address. Therefore,
whenever a pointer is assigned to an int variable, the values of the 64-bit
pointer and the 32-bit variable will always be identical (except in the special
situations described in Section A.2.2).
Figure A–1 is an example of a memory diagram of programs that use the
-taso and -call_shared options. (If you invoke the linker through the
Not accessible
Mappable by program
Text section
0x0000 0000 1200 0000
0x0000 0000 11ff ffff
Stack (grows towards zero)
$sp
Mappable by program
0x0000 0000 0001 0000
Not accessible (by convention) 0x0000 0000 0000 ffff
0x0000 0000 0000 0000
ZK-0876U-AI
Note that stack and heap addresses will also fit into 31 bits. The stack grows
downward from the bottom of the text segment, and the heap grows upward
from the top of the data segment.
The -T and -D options (linker options that are used to set text and data
segment addresses, respectively) can also be used to ensure that the text and
data segments of an application are loaded into low memory. The -taso
option, however, in addition to setting default addresses for text and data
segments, also causes shared libraries linked outside the 31-bit address
space to be appropriately relocated by the loader.
• Specifying the -shared option with the -taso option results in the
following defaults:
Using these default values produces sufficient amounts of space for text
and data segments for most applications (see the Object File/Symbol Table
Format Specification for details on the contents of text and data segments).
The default values also allow an application to allocate a large amount of
mmap space.
If you specify the -taso option and also specify text and data segment
address values with -T and -D , the values specified override the -taso
default addresses.
You can use the odump utility to check whether a program was built
successfully within 31-bit address space. To display the start addresses of
the text, data, and bss segments, enter the following command:
% odump -ov obj_file_x.o
None of the addresses should have any bits set in bits 31 to 63; only bits
0 to 30 should ever be set.
Shared objects built with -taso cannot be linked with shared objects that
were not built with -taso. If you attempt to link taso shared objects with
nontaso shared objects, the following error message is displayed:
Cannot mix 32 and 64 bit shared objects without -taso option
This option equates the name of the mmap function with the name
of a jacket routine (_mmap_32_). As a result, the jacket routine
is invoked whenever references are made to the mmap function in
the source program.
2. If the mmap function is invoked in only one of the source
modules, either include the jacket routine in that module or
create an mmap_32.o object module and specify it on the cc
command line. (The file specification for the jacket routine is
/usr/opt/alt/usr/lib/support/mmap_32.c, and the file
resides in the optional software subset CMPDEVENHnnn.)
If the mmap function is invoked from more than one source file, you
must use the method of creating an mmap_32.o object module and
specifying it on a cc command line because including the jacket
routine in more than one module would generate linker errors.
unlink()
system call
table
User Process
Base System default system
partition
unlink() kernel
default
.. system calls
.
libsys5.a SVID
system
User Process vector
unlink() SVID calls
table
System V partition
Habitat
unlink()
..
.
ZK-0814U-AI
The cc and ld commands that reside in the System V habitat are shell
scripts that, when specified, add several options to the default system cc
and ld commands before the commands are executed.
The cc command automatically inserts the -Ipath option on the command
line to specify the use of the SVID versions of system header files. For
example, the /usr/include file is used instead of the default version.
System header files that do not have SVID differences are obtained from
the default location.
The cc and ld commands automatically include the following options:
• The -Lpath option provides the path of the System V libraries.
• The -lsys5 option indicates that the libsys5.a library should be
searched before the standard C library to resolve system call and
subroutine references.
• The -D_ _SVID_ _ option selectively turns on SVID specific behavior
from the default system.
The System V cc command takes the preceding command line and adds
the necessary options to search the System V habitat libraries, which are
searched prior to the default libraries. It also includes any existing System
V header files instead of the standard header files for /usr/include.
Hence, if your environment is set to SVID 2, the preceding command line is
processed as follows:
/bin/cc -D__SVID__ -I$SVID2PATH/usr/include -L$SVID2PATH/usr/lib \
−non_shared −L/local/lib src.c −lm −lloc −lsys5
Using this command line, libraries are searched in the following order:
1. /usr/lib/libm.a
2. /local/lib/libloc.a
3. SVID2PATH/usr/lib/libsys5.a
4. /usr/lib/libc.a
The libraries that are searched and the order that they are searched in
depends on the function you are performing. For more information, see
cc(1) and ld(1).
size= 10
size= 0 10
*table=NULL
ZK-0973U-AI
Note that the size attribute in Figure C–1 receives its initial value from
the sysconfigtab database even though the subsystem initializes the
size attribute to 0 (zero).
Using an attribute table declared in the subsystem code, you control which
of the subsystem’s attribute values can be set at initial configuration. (For
information about how you control the attributes that can be set in the
sysconfigtab database, see Section C.2.)
In addition to being able to store attribute values for initial configuration,
system administrators can query and reconfigure attribute values at any
time when the subsystem is configured into the kernel. During a query
request, attribute values are returned to the system administrator. During
a reconfiguration request, attribute values are modified. How the return
or modification occurs depends upon how attributes are declared in the
subsystem code:
The following sections explain both types of attribute tables by showing and
explaining their declaration in /sys/include/sys/sysconfig.h.
1 The name of the attribute is stored in the name field. You choose
this name, which can be any string of alphabetic characters, with a
length between two and the value stored in the CFG_ATTR_NAME_SZ
constant. The CFG_ATTR_NAME_SZ constant is defined in the
/sys/include/sys/sysconfig.h file.
2 You specify the attribute data type in this field, which can be one of
the data types listed in Table C–1.
4 The address field determines whether the kernel has access to the
value of the attribute.
If you specify an address in this field, the kernel can read and modify the
value of the attribute. When the kernel receives a query request from
the sysconfig command, it reads the value in the location you specify
in this field and returns that value. For a configure or reconfigure
request, the kernel checks for the following conditions:
• The data type of the new value is appropriate for the attribute.
• The value falls within the minimum and maximum values for the
attribute.
If the value meets these requirements, the kernel stores the new value
for the attribute. (You specify minimum and maximum values in the
next two fields in the attribute definition.)
In some cases, you want or need to respond to query, configure, or
reconfigure requests for an attribute in the subsystem code. In this
case, specify a NULL in this field. For more information about how you
control attribute values, see Section C.3.
5 The min and max fields define the minimum and maximum allowed
values for the attribute. You choose these values for the attribute.
The kernel interprets the contents of these two fields differently,
depending on the data type of the attribute. If the attribute is one of the
integer data types, these fields contain minimum and maximum integer
values. For attributes with the CFG_ATTR_STRTYPE data type, these
fields contain the minimum and maximum lengths of the string. For
attributes with the CFG_ATTR_BINTYPE data type, these fields contain
the minimum and maximum numbers of bytes you can modify.
6 If you want the kernel to be able to read and modify the contents of a
binary attribute, you use the binlength field to specify the current size
of the binary data. If the kernel modifies the length of the binary data
stored in the attribute, it also modifies the contents of this field.
#include <sys/sysconfig.h>
#include <sys/errno.h>
/*
* Initialize attributes
*/
static char name[] = "Default Table";
static int size = 0;
static long *table = NULL;
/*
* Declare attributes in an attribute table
*/
cfg_subsys_attr_t table_mgr_attrbutes[] = {
/*
* "name" is the name of the table
*/
{"name", 1 CFG_ATTR_STRTYPE, 2
CFG_OP_CONFIGURE | CFG_OP_QUERY | CFG_OP_RECONFIGURE, 3
(caddr_t) name, 4 2, sizeof(name), 5 0 6 },
/*
* "size" indicates how large the table should be
*/
{"size", CFG_ATTR_INTTYPE,
CFG_OP_CONFIGURE | CFG_OP_QUERY | CFG_OP_RECONFIGURE,
NULL, 1, 10, 0},
/*
* "table" is a binary representation of the table
*/
{"table", CFG_ATTR_BINTYPE,
CFG_OP_QUERY,
NULL, 0, 0, 0},
/*
* "element" is a cell in the table array
*/
{"element", CFG_ATTR_LONGTYPE,
CFG_OP_QUERY | CFG_OP_RECONFIGURE,
NULL, 0, 99, 0},
{,0,0,0,0,0,0} /* required last element */
};
1 The name of the attribute is stored in the name field, which is initialized
to Default Table by the data declaration that precedes the attribute
table.
2 The attribute data type is CFG_ATTR_STRTYPE, which is a
null-terminated array of characters.
3 This field specifies the operations that can be performed on the attribute.
In this case, the attribute can be configured, queried, and reconfigured.
4 This field determines whether the kernel has access to the value of
the attribute.
If you specify an address in this field, as shown in the example, the
kernel can read and modify the value of the attribute. When the kernel
receives a query request from the sysconfig command, it reads the
value in the location you specify in this field and returns that value. For
a configure or reconfigure request, the kernel checks that the data type
of the new value is appropriate for the attribute and that the value falls
within the minimum and maximum values for the attribute. If the
value meets these requirements, the kernel stores the new value for the
attribute. (You specify minimum and maximum values in the next two
fields in the attribute definition.)
5 These two fields define the minimum allowed value for the attribute
(in this case, 2), and the maximum allowed value for the attribute (in
this case, sizeof(name)).
If you want the minimum and maximum values of the attribute to be
set according to the system minimum and maximum values, you can
use one of the constants defined in the /usr/include/limits.h file.
1 The name field specifies the name of the attribute, following the same
attribute name rules as the name field in the definition attribute table.
2 The type field specifies the data type of the attribute. Table C–1 lists
the possible data types.
3 The status field contains a predefined status code. Table C–3 lists
the possible status values.
1 The op variable contains the operation code, which can be one of the
following:
CFG_OP_CONFIGURE
CFG_OP_QUERY
CFG_OP_RECONFIGURE
CFG_OP_UNCONFIGURE
attributes = (cfg_attr_t*)indata; 2
if (!strcmp("size", attributes[i].name)){ 5
/* Set the size of the table */
table = (long *) kalloc(attributes[i].attr.num.val*sizeof(long)); 6
/*
* Make sure that memory is available
*/
if (table == NULL) { 7
attributes[i].status = CFG_ATTR_EMEM;
continue;
}
/*
* Success, so update the new table size and attribute status
*/
case CFG_OP_QUERY:
/*
* indata is a list of attributes to be queried, and
* indata_size is the count of attributes
*/
attributes = (cfg_attr_t *) indata; 1
/*
* We need to handle the query for the following
* attributes.
*/
if (!strcmp(attributes[i].name, "size")) { 4
/*
* Fetch the size of the table.
*/
attributes[i].attr.num.val = (long) size;
attributes[i].status = CFG_ATTR_SUCCESS;
continue;
}
if (!strcmp(attributes[i].name, "table")) { 5
/*
* Fetch the address of the table, along with its size.
*/
attributes[i].attr.bin.val = (caddr_t) table;
attributes[i].attr.bin.val_size = size * sizeof(long);
attributes[i].status = CFG_ATTR_SUCCESS;
continue;
}
if (!strcmp(attributes[i].name, "element")) { 6
/*
* Fetch the element.
*/
attributes[i].attr.num.val = table[attributes[i].index - 1];
attributes[i].status = CFG_ATTR_SUCCESS;
continue;
}
}
}
break;
.
.
.
case CFG_OP_RECONFIGURE:
/*
* The indata parameter is a list of attributes to be
* reconfigured, and indata_size is the count of attributes.
*/
attributes = (cfg_attr_t *) indata; 1
/*
* We need to handle the reconfigure for the following
* attributes.
*/
if (!strcmp(attributes[i].name, "size")) { 4
long *new_table;
int new_size;
/*
* Change the size of the table.
*/
new_size = (int) attributes[i].attr.num.val; 5
new_table = (long *) kalloc(new_size * sizeof(long));
/*
/*
* Update the new table with the contents of the old one,
* then free the memory for the old table.
*/
if (size) { 7
bcopy(table, new_table, sizeof(long) *
((size < new_size) ? size : new_size));
kfree(table);
}
/*
* Success, so update the new table address and size.
*/
table = new_table; 8
size = new_size;
attributes[i].status = CFG_ATTR_SUCCESS;
continue;
}
if (!strcmp(attributes[i].name, "element")) { 9
/*
* Make sure that the index is in the right range.
*/
if (attributes[i].index < 1 || attributes[i].index > size) { 10
attributes[i].status = CFG_ATTR_EINDEX;
continue;
}
/*
* Update the element.
*/
table[attributes[i].index - 1] = attributes[i].attr.num.val; 11
attributes[i].status = CFG_ATTR_SUCCESS;
continue;
}
}
}
break;
.
.
.
case CFG_OP_SUBSYS_MIN:
/*
* Double each element of the table.
*/
for (i=0; ((table != NULL) && (i < size)); i++)
table[i] *= 2;
break;
.
.
.
}
The code doubles the value of each element in the table.
case CFG_OP_UNCONFIGURE:
/*
* Free up the table if we allocated one.
*/
if (size)
kfree(table, size*sizeof(long));
return ESUCCESS;
}
This portion of the configuration routine determines whether memory has
been allocated for a table. If it has, the routine frees the memory using
kfree function.
size = 0;
break;
}
return ESUCCESS;
The subsystem configuration routine returns ESUCCESS on completing
a configuration, query, reconfigure, or unconfigure request. The way
this subsystem is designed, no configuration, query, reconfiguration, or
unconfiguration request, as a whole, fails. As shown in the examples in
Section C.3.1 and Section C.3.3, operations on individual attributes might
fail.
In some cases, you might want the configuration, reconfiguration, or
unconfiguration of a subsystem to fail. For example, if one or more key
attributes failed to be configured, you might want the entire subsystem
configuration to fail. The following example shows a return that has an
error value:
switch(op){
.
.
.
if (table == NULL) {
attributes[i].status = CFG_ATTR_EMEM;
return ENOMEM; /*Return message from errno.h*/
}
The if statement in the example tests whether memory has been allocated
for the table. If no memory has been allocated for the table, the subsystem
returns with an error status and the configuration of the subsystem fails.
1. Move the subsystem source files into a directory in the /usr/sys area:
# mkdir /usr/sys/mysubsys
# cp table_mgr.c /usr/sys/mysubsys/table_mgr.c
# cp table_data.c /usr/sys/mysubsys/table_data.c
You can replace the mysubsys directory name with the directory name
of your choice.
2. Edit the /usr/sys/conf/files file using the text editor of your choice
and insert the following lines:
#
# table_mgr subsystem
#
MODULE/DYNAMIC/table_mgr optional table_mgr Binary
mysubsys/table_mgr.c module table_mgr
mysubsys/table_data.c module table_mgr
The entry in the files file describes the subsystem to the config
program. The first line of the entry contains the following information:
• The MODULE/DYNAMIC/table_mgr token indicates that the
subsystem is a dynamic kernel module (group of objects) named
table_mgr.
• The optional keyword indicates that the subsystem is not required
into the kernel.
• The table_mgr identifier is the token that identifies the subsystem
on the sysconfig and autosysconfig command lines. Use
caution when choosing this name to ensure that it is unique with
1. Move the subsystem source files into a directory in the /usr/sys area:
For purposes of testing the kernel subsystem, enter a new name for the
configuration file, such as MYSYS.TEST. Giving the doconfig program
a new configuration file name allows the existing configuration file to
remain on the system. You can then use the existing configuration file
to configure a system that omits the subsystem you are testing.
5. Select option 15 from the Kernel Option Selection menu. Option 15
indicates that you are adding no new kernel options.
(dbx)
2. Enter the sysconfig command to initially configure the subsystem:
# sysconfig -c table_mgr
3. Enter the addobj command as shown:
(dbx) addobj /subsys/table_mgr.mod
(dbx) p &table_mgr_configure
0xffffffff895aa000
If you want to set a breakpoint in the portion of the subsystem code that
initially configures the subsystem, you must enter the addobj command
following the load of the subsystem, but before the kernel calls the
configuration routine. To stop execution between the load of the subsystem
and the call to its configuration routine, set a breakpoint in the special
routine, subsys_preconfigure. The following procedure shows how to set
this breakpoint:
Note that the modifiers themselves cannot be broken over several lines. For
example, the earlier code could not be written as:
#pragma parallel
#pragma if(test_function()) local(var1,
#pragma var2, var2)
A loop that executes in parallel must obey certain properties. These include:
• The index variable is not modified by the loop except by the third
expression of the for statement. Further, that expression must always
adjust the index variable by the same amount.
• Each iteration of the loop must be independent. That is, the computations
performed by one iteration of the loop must not depend on the results
of another iteration
• The number of iterations of the loop is known before the loop starts.
The programmer is responsible for verifying that the parallel loops obey
these restrictions.
Another use of parallel processing is to have several different blocks of code
run in parallel. The #pragma psection and #pragma sections directives
are used for this purpose. The following code shows how these directives
might be used:
Once again, certain restrictions apply to the code block. For example, one
code block must not rely on computations performed in other code blocks.
The final type of code that can appear in a parallel region is serial code. Serial
code is neither within a #pragma pfor nor a #pragma psection. In this
case, the same code will be executed by all of the threads created to execute
the parallel region. While this may seem wasteful, it is often desirable to
place serial code between two #pragma pfor loops or #pragma psection
blocks. Although the serial code will be executed by all of the threads, this
construct is more efficient than closing the parallel region after the first
pfor or psection and opening another before the second one. This is due to
run-time overhead associated with creating and closing a parallel region.
Be careful when placing serial code in a parallel region. Note that the
following statements could produce unexpected results:
a++;
b++
Unexpected results may occur because all threads will execute the
statements, causing the variables a and b to be incremented some number
of times. To avoid this problem, enclose the serial code in a #pragma one
processor block. For example:
#pragma one processor
{
a++;
b++
}
Note that no thread can proceed past the code until it has been executed.
As the syntax shows, the #pragma pfor must be followed by the iterate
modifier. The iterate-expressions takes a form similar to a for loop:
index-variable = expr1 ; expr2 ; expr3
The schedtype option tells the run-time scheduler how to partition the
iterations among the available threads. Valid schedule-type values are:
• simple — The scheduler will partition the iterations evenly among all of
the available threads. This is the default.
• dynamic — The scheduler will give each thread the number of iterations
specified by the chunksize expression.
• interleave — This is the same as dynamic except that the work is
assigned to the threads in an interleaved way.
#pragma section
stmt1
#pragma section
stmt2. . .
#pragma section
stmtn
}
The name is an identifier that designates each gate. The names of gates are
in their own name space; for example, a gate name of foo is distinct from a
variable named foo. A gate name is not declared before it is used.
This type of synchronization operates as follows: No thread can execute
the statement after the #pragma exit gate until all threads have passed
the matching #pragma enter gate.
The manner in which devices and device special files are named and
organized was changed in Version 5.0 of the Tru64 UNIX operating system.
For details on these changes, see dsfmgr(8) and the System Administration
manual. Also, see the Installation Guide for information on the effects that
various installation operations have on the accessibility of new- and old-style
device special file names.
To support the changes that affect device handling, the operating system
provides conversion routines that make it relatively easy to handle the
transition between the new- and old-style names. This appendix documents
those routines. These routines will continue to be provided until the old-style
names are no longer supported by the system.
System components or applications that reference the names of device
special files will need to modify their source code. The modifications can be
done, as necessary, either by replacing all device special file names with their
new names or by using the conversion routines to derive the new names.
The following rules apply to all of the conversion routines:
• Arguments will be returned if their pointers in the functions calls are
non-null.
• Only the first argument is mandatory. However, the functions will not
return useful information, except status information, unless other
arguments are specified.
The individual routines — dsfcvt_btoc( ), dsfcvt_ctob( ),
dsfcvt_ntoo( ), dsfcvt_oton( ), dsfcvt_noro( ), and
dsfcvt_cdevtoname( ) — are described in the following list. Descriptions
of the parameters follow the routine descriptions.
dsfcvt_btoc() Convert block name to character name. The block
device name is searched for in the device status
database, and, if found, the corresponding character
device name is then searched for. If it is found, the
name is returned along with the hardware ID.
The following list provides information about the arguments to the functions:
F.1.1 Overview
The -om postlink optimizer performs the following code optimizations:
• Removal of nop (no operation) instructions; that is, those instructions
that have no effect on machine state.
• Removal of .lita data; that is, that portion of the data section of an
executable image that holds address literals for 64-bit addressing.
Using available options, you can remove unused .lita entries after
optimization and then compress the .lita section.
• Reallocation of common symbols according to a size that you determine.
-WL, -om_compress_lita
-WL, -om_dead_code
-WL, -om_feedback
-WL, -om_Gcommon,num
-WL, -om_ireorg_feedback,file
-WL, -om_no_inst_sched
-WL, -om_no_align_labels
-WL, -om_split_procedures
The -om option is most effective when used with the −non_shared option —
that is, with executables. For example:
% cc -non_shared -O3 -om prog.c
1 When the program is compiled with the -feedback option for the
first time, a special augmented executable file is created. It contains
information that the compiler uses to relate the executable to the source
files. It also contains a section that is used later to store profiling
feedback information for the compiler. This section remains empty after
the first compilation, because the pixie profiler has not yet generated
any feedback information (step 2). Make sure that the file name
You might want to run your instrumented program several times with
different inputs to get an accurate picture of its profile. The following
example explains how to merge profiling statistics from two runs of a
program, prog, whose output varies from run to run with different sets
of input:
% cc -feedback prog -o prog -non_shared -O3 *.c 1
% pixie -pids prog 2
% prog.pixie 3
(input set 1)
% prog.pixie
(input set 2)
% prof -pixie -update prog prog.Counts.* 4
% cc -feedback prog -o prog -non_shared -om -O3 *.c 5
1 The shared library is compiled with the -g1 option to give feedback
data for each source line.
2 A program to exercise the important parts of the library is built.
3 The shared library and program are instrumented and run to profile
them.
4 A feedback file is generated for just the shared library.
5 The shared library is recompiled, relinked, and reordered to optimize
the performance of the code that the profile shows is most heavily used.
Index–1
linking files compiled with, 2–21 setting in procedures, 5–42
ASM, 2–28 built-in data types
assert directive use in dbx commands, 5–10
pragma assert directive, 3–2 built-in function
assign command (dbx), 5–38 pragma counterpart, 3–15
-assume noaccuracy_sensitive option byte ordering
(cc) supported by Tru64 UNIX, 2–4
( See -fp_reorder option )
–assume noaligned_objects, 10–17
C
Atom tools, 9–1
command syntax, 9–2, 9–3 C compiler, 2–1
developing, 9–6 C language, program checking
examples of, 9–1 data type, 6–4
running Atom tools, 9–1 external names, 6–11
testing tools under development, function definitions, 6–5
9–3 functions and variables, 6–6
using installed tools, 9–1 initializing variables, 6–9
attribute migration, 6–10
defined, C–2 portability, 6–10
example of defining, C–9 structure, union, 6–5
initial value assignment, C–2 use of characters, 6–11
attribute data types, C–6 use of uninitialized variables, 6–9
attribute request codes, C–6 -c option (cc)
attribute table compiling multilanguage programs,
contents of, C–4 2–16
automatic decomposition -c option (dbx), 5–8
use in KAP, 10–12 C preprocessor, 2–9
implementation-specific directives,
B 2–11
including common files, 2–9
backward compatibility multilanguage include files, 2–11
shared libraries, 4–18 predefined macros, 2–9
binary incompatibility C programs
shared libraries, 4–18 optimization considerations, 10–1
binlog and syslog c_excpt.h header file, 11–3
interaction with EVM, 14–5 cache collision, data
32-bit applications avoiding, 8–12
reducing memory usage, 10–19 cache collisions, data
bit fields, 6–11 avoiding, 10–16
breakpoints cache misses
continuing from, 5–37 avoiding, 10–19
setting, 5–41 cache misses, data
setting conditional breakpoints, profiling for, 8–12
5–42 cache thrashing
Index–2
preventing, 8–12, 10–16 cfg_subsys_attr_t data type, C–5
cache usage characters
coding suggestions, 10–16 use in a C program, 6–11
improving with cord, F–4 –check_omp option (cc), 13–2
call command (dbx), 5–39 cma_debug() command (dbx), 5–58
call-graph profiling, 8–5 coding errors
callback functions (EVM), 14–5 checking performed by lint, 6–12
calls coding suggestions
( See procedure calls ) C-specific considerations, 10–17
catch command (dbx), 5–46 cache usage patterns, 10–16
cc command data alignment, 10–16
compilation control options, 2–12 data types, 10–14
debugging option, 5–6 library routine selection, 10–12
default behavior, 2–12 sign considerations, 10–18
-g and -O options for profiling, 8–4 command-line editing (dbx), 5–13
invoking the linker, 2–20 common file
-p option, 8–11, 8–16 ( See header file )
-pg option, 8–5, 8–10 Compaq Extended Math Library
setting default alignment, 3–27 how to access, 10–12
specifying additional libraries, compiler commands
2–20 invoking the linker, 1–4
specifying function inlining, 3–14 compiler optimizations
specifying search path for libraries, improving with feedback file, 10–8,
2–3 F–2, F–4
-taso option, A–4 recommended optimization levels,
using in System V habitat, B–1 10–2
CFG_ATTR_BINTYPE data type, C–6 use of -O option (cc), 10–2
CFG_ATTR_INTTYPE data type, C–6 compiler options (cc), 2–12
CFG_ATTR_LONGTYPE data type, compiler system, 2–1
C–6 ANSI name space cleanup, 2–26
CFG_ATTR_STRTYPE data type, C compiler environments, 2–12
C–6 C preprocessor, 2–9
CFG_ATTR_UINTTYPE data type, driver programs, 2–2
C–6 linker, 2–19
CFG_ATTR_ULONGTYPE data type, object file tools, 2–23
compiling applications
C–6
in System V habitat, B–1
CFG_OP_CONFIGURE request code,
completion handling, 11–5
C–6
compound pointer, A–1
CFG_OP_QUERY request code, C–6
conditional code
CFG_OP_RECONFIGURE request
writing in dbx, 5–45
code, C–6
cont command (dbx), 5–37
Index–3
conti command (dbx), 5–37 casts, 6–6
cord utility, F–4 coding suggestions, 10–14
core dump file effect of -O option (cc), 10–2
naming, 5–54 floating-point range and processing,
specifying for dbx, 5–4, 5–7 2–5
specifying the location of shared for attributes, C–6
libraries for, 5–26 mixing, 6–4
critical directive, D–9 sizes, 2–4
Ctrl/Z data types, built-in
symbol name completion in dbx, use in dbx commands, 5–10
5–15 data types, variable (EVM), 14–16
CXML dbx commands, 5–1
how to access, 10–12 ( See also dbx debugger )
args, 5–33
D cma_debug(), 5–58
and ?, 5–31
data alignment alias, 5–23
coding suggestions, 10–16 assign, 5–38
data allocation call, 5–39
coding suggestions, 10–18 catch, 5–46
data cache collision cont, 5–37
avoiding, 8–12 conti, 5–37
data cache collisions
delete, 5–25
avoiding, 10–16
disable, 5–25
data cache misses
down, 5–29
profiling for, 8–12
dump, 5–49
data flow analysis
edit, 5–32
compilation optimizations, 10–2
data reuse enable, 5–25
handling efficiently, 10–12 file, 5–30
data segment func, 5–29
effect of -taso option, A–6 goto, 5–36
data sets, large ignore, 5–46
handling efficiently, 10–12 list, 5–30
data structures listobj, 5–26
allocation suggestions, 10–16 next, 5–35
data type nexti, 5–35
alignment in structures, 2–5 patch, 5–38
modifying alignment, 2–8 playback input, 5–51
types supported by Tru64 UNIX, playback output, 5–53
2–4 print, 5–47
data types printregs, 5–48
array, 6–5 quit, 5–9
array pointer, 6–5 record input, 5–51
Index–4
record output, 5–53 invoking a shell from dbx, 5–27
rerun, 5–33 invoking an editor, 5–32
return, 5–36 LINEEDIT option, 5–13, 5–15
run, 5–33 operator precedence, 5–10
set, 5–15 predefined variables, 5–17
setenv, 5–40 repeating commands, 5–12
sh, 5–27 .dbxinit file, 5–7
source, 5–51 debugger
status, 5–24 ( See dbx debugger )
step, 5–35 debugging
stepi, 5–35 general concepts, 5–3
stop, 5–41 kernel debugging (-k option), 5–8
stopi, 5–41 programs using shared libraries,
tlist, 5–57 4–15
trace, 5–43 debugging tools, 1–5
tracei, 5–43 ( See also Ladebug debugger;
tset, 5–57 Third Degree; dbx debugger;
tstack, 5–28, 5–57 lint )
unalias, 5–23 supported by Tru64 UNIX, 1–5
unset, 5–15 decomposition
up, 5–29 use in KAP, 10–12
use, 5–27 delete command (dbx), 5–25
whatis, 5–33 development tools, software (Tru64
when, 5–45 UNIX), 1–4
where, 5–28 device special file names
whereis, 5–32 converting old-style and new-style,
which, 5–32 E–1
dbx debugger, 1–5, 5–1 -D_FASTMATH option (cc), 10–13
( See also dbx commands ) -D_INLINE_INTRINSICS option (cc),
built-in data types, 5–10 10–13
command-line editing, 5–13 -D_INTRINSICS option (cc), 10–13
direct I/O
command-line options, 5–7
use to improve performance, 10–14
compile command option (-g), 5–6
direct memory access
completing symbol name (Ctrl/Z),
( See DMA )
5–15
directed decomposition
debugging techniques, 5–4
use in KAP, 10–12
EDITMODE option, 5–13 directive
EDITOR option, 5–13 pragma assert directives, 3–2
entering multiple commands, 5–14 pragma environment, 3–6
-g option (cc), 5–6 pragma extern_model directives,
initialization file (dbxinit), 5–7 3–7
Index–5
pragma extern_prefix, 3–11 dbx command-line editing, 5–13
pragma function, 3–14 editor
pragma inline, 3–13 invoking from dbx, 5–32
pragma intrinsic, 3–14 EDITOR variable
pragma linkage, 3–16 dbx command-line editing, 5–13
pragma member_alignment, 3–19 enable command (dbx), 5–25
pragma message, 3–20 endian byte ordering
pragma optimize, 3–25 supported by Tru64 UNIX, 2–4
pragma pack, 3–27 enter gate directive, D–10
pragma pointer_size, 3–28 enumerated data type, 6–6
pragma use_linkage, 3–29 environment directive
pragma weak, 3–30 pragma environment directive, 3–6
directives environment variables
ifdef, 2–11 EDITMODE, 5–13
include, 2–10 EDITOR, 5–13
directories LINEEDIT, 5–13
linker search order, 2–21 MP_CHUNK_SIZE, D–11
directories, source MP_SPIN_COUNT, 13–3, D–11
specifying in dbx, 5–27 MP_STACK_SIZE, 13–3, D–11
dis (object file tool), 2–26 MP_THREAD_COUNT, 13–3,
disable command (dbx), 5–25 D–11
disk files, executable MP_YIELD_COUNT, 13–4, D–11
patching in dbx, 5–38 PROFFLAGS, 8–30
distribution media setting in dbx, 5–40
loading applications on, 1–7 Event Manager
DMA ( See EVM )
use by direct I/O, 10–14 event poster (EVM)
-D option definition, 14–2
use with -taso option, A–6 event subscriber (EVM)
down command (dbx), 5–29 definition, 14–2
driver program event templates
compiler system, 2–2 how to create, 14–20
dsfcvt* routines, E–1 events (EVM), 14–1
dump command (dbx), 5–49 ( See also EVM )
dynamically configurable subsystem authorization to send or receive,
creating, C–1 14–5
defined, C–2 contents of, 14–6
data items, 14–6
designing, 14–17
E
event names, 14–7
edit command (dbx), 5–32 event priority, 14–13
editing event reception filters, 14–31
command-line editing in dbx, 5–13 format data item, 14–12
EDITMODE variable EVM, 14–1
Index–6
( See also EVM functions; events EvmItemSetVa, 14–34e
(EVM) ) EvmVarGet, 14–35e
callback functions, 14–5 EvmVarRelease, 14–35e
event poster EvmVarSet, 14–35e
definition, 14–2 exception
event reception filters, 14–31 definition, 11–1
event subscriber frame-based, 11–5
definition, 14–2 structured, 11–5
header file requirements, 14–26 exception code, 11–6
interaction with binlog and syslog, exception filter, 11–5
14–5 exception handler
programming interface, 14–26 locating on the run-time stack,
return status codes, 14–26 11–6
starting and stopping, 14–5 exception handling
EVM commands application development
evmget, 14–3 considerations, 11–1
EVM functions floating-point operations
EvmConnCheck, 14–45e performance considerations,
EvmConnControl, 14–52e 10–5
EvmConnCreate, 14–38e header files, 11–3
EvmConnDestroy, 14–38e exception_code function, 11–6
EvmConnDispatch, 14–42e exception_info function, 11–6
EvmConnFdGet, 14–45e excpt.h header file, 11–3
EvmConnSubscribe, 14–42e executable disk files
EvmConnWait, 14–42e patching in dbx, 5–38
EvmEventCreate, 14–32e executable program
EvmEventCreateVa, 14–34e creating, 2–3, 2–20
EvmEventDestroy, 14–32e running, 2–22
EvmEventFormat, 14–42e exit gate directive, D–10
EvmEventNameMatch, 14–51e expressions
EvmEventNameMatchStr, 14–51e displaying values in dbx, 5–37,
EvmEventPost, 14–38e 5–47
EvmEventRead, 14–40e operator precedence in dbx, 5–10
EvmEventValidate, 14–40e extern_model directive
EvmEventWrite, 14–40e pragma extern_model directive,
EvmFilterCreate, 14–48e 3–7
extern_prefix directive
EvmFilterDestroy, 14–48e
pragma extern_prefix directive,
EvmFilterSet, 14–48e
3–11
EvmFilterTest, 14–48e
external names, 6–11
EvmItemGet, 14–32e
external references
EvmItemRelease, 14–32e
EvmItemSet, 14–32e
Index–7
reducing resolution during linking, G
10–2
-G option (cc), 10–4
-g option (cc), 5–6, 8–4
F goto command (dbx), 5–36
-fast option (cc), 10–4 gprof, 8–1, 8–5, 8–10
feedback files ( See also profiling )
profile-directed optimization, 10–8, –granularity option (cc), 13–2
F–2, F–4
profile-directed reordering with H
cord, F–4
-feedback option (cc), 10–4, 10–8, handling exceptions, 11–1
F–2 header file
-feedback option (pixie), F–4 including, 2–9
header files
file (object file tool), 2–25
c_excpt.h, 11–3
file command (dbx), 5–30
file names excpt.h, 11–3
suffixes for programming language fpu.h, 11–3
files, 2–3 multilanguage, 2–11
file sharing pdsc.h, 11–3
effects on performance, 10–6 standards conformance in, 1–3
files heap memory analyzer
( See archive files; executable and profiling, 8–21
disk files; header files; object hiprof, 8–1, 8–5, 8–11, 8–15, 9–2
files; source files ) ( See also profiling )
fixso utility, 4–14
floating-point operations I
exception handling, 10–5
-fp_reorder option (cc), 10–2 -i option (dbx), 5–8
use of KAP, 10–12 -I option (dbx), 5–8
floating-point operations (complicated) -ieee option (cc), 10–5
use of CXML, 10–12 IEEE floating-point
floating-point range and processing ( See floating-point range and
IEEE standard, 2–5 processing )
format data item (EVM), 14–12 ifdef directive
-fp_reorder option (cc), 10–2, 10–4 for multilanguage include files,
fpu.h header file, 11–3 2–11
frame-based exception handling, 11–5 -ifo option (cc), 10–2, 10–4
func command (dbx), 5–29 ignore command (dbx), 5–46
function directive image activation in dbx, 5–42
pragma function directive, 3–14 include file
functions ( See header file )
checking performed by lint, 6–6 inline assembly code (ASM), 2–28
inline directive
Index–8
pragma inline directive, 3–13 -k option, 5–8
-inline option (cc), 10–4 Kuck & Associates Preprocessor
inlining, procedure ( See KAP )
compilation optimizations, 10–2
-D_INLINE_INTRINSICS option
L
(cc), 10–13
installation tools, 1–6 ladebug debugger, 5–1
instruction and source line profiling, large data sets
8–11 handling efficiently, 10–12
instruction set, Alpha ld command, 2–20
using non-native instructions, linking taso shared objects, A–6
10–14 specifying -taso option, A–4
integer division using in System V habitat, B–1
substituting floating-point division, ld linker
10–14 handling assembly language files,
integer multiplication 2–21
substituting floating-point linking object files, 1–4
multiplication, 10–14 linking with shared libraries, 4–7
internationalization using directly or through cc, 2–19
developing applications, 1–3 leave statement, 11–13
interprocess communications libc.so default C library, 2–21
( See IPC ) libexc exception library, 11–1
pipes, 1–7 libpthread.so, 12–2
signals, 1–7 libraries
sockets, 1–7 shared, 4–1
STREAMS, 1–7 library
System V IPC, 1–7 linking programs with, 2–21
threads, 1–7 run-time, 2–21
X/Open Transport Interface (XTI), library description files (lint), 6–14
1–7 library selection
intrinsic directive effect on performance, 10–12
pragma intrinsic directive, 3–14 limiting search paths, 4–7
ISO standards limits.h file, C–9
application development LINEEDIT variable
considerations, 1–2 dbx command-line editing, 5–13
dbx symbol name completion, 5–15
K linkage directive
pragma linkage directive, 3–16
-k option (dbx), 5–8 linker
KAP ( See ld linker )
usage recommendation, 10–12 linking applications
kernel debugging by using compiler command, 2–20
Index–9
in System V habitat, B–1 displaying contents in dbx, 5–50
linking options tuning memory usage, 10–18
effects of file sharing, 10–6 memory access
lint, 6–1 detecting uninitialized or invalid,
coding error checking, 6–12 7–1
coding problem checker, 6–1 message directive
command syntax, 6–1 pragma message directive, 3–20
creating a lint library, 6–14 messages, IPC
data type checking, 6–4 ( See System V IPC )
error messages, 6–16 –misalign, 10–17
increasing table size, 6–13 misaligned data
migration checking, 6–10 ( See unaligned data )
options, 6–1 misses, cache
portability checking, 6–10 avoiding, 10–19
mmap system call
program flow checking, 6–3
shared libraries, 4–17
variable and function checking, 6–6
use with -taso option, A–7
warning classes, 6–21
-module_path option (dbx), 5–8
list command (dbx), 5–30
-module_verbose option (dbx), 5–8
listobj command (dbx), 5–26
load time moncontrol routine, 8–31
reducing shared library load time, sample code, 8–31
monitor routines
10–6
loadable subsystem for controlling profiling, 8–30
defined, C–2 monitor_signal routine, 8–31
loader sample code, 8–34
search path of, 4–4 monitoring tools, 8–1
long pointer, A–1 monstartup routine, 8–30
loops sample code, 8–31
KAP optimizations, 10–12 –mp option (cc), 13–1
lint analysis of, 6–4 MP_CHUNK_SIZE variable, D–11
MP_SPIN_COUNT variable, 13–3,
D–11
M MP_STACK_SIZE variable, 13–3,
macros D–11
predefined, 2–9 MP_THREAD_COUNT variable,
magic number, 2–25 13–3, D–11
malloc function MP_YIELD_COUNT variable, 13–4,
tuning options, 10–18 D–11
use with -taso option, A–7 mpc_destroy routine, 13–5
member_alignment directive multilanguage program
pragma member_alignment compiling, 2–16
directive, 3–19 include files for, 2–11
memory multiprocessing, symmetrical
detecting leaks, 7–1, 8–21 ( See SMP )
Index–10
multithreaded application -Olimit option (cc), 10–4
building, 12–11 -om
developing libraries for, 12–1 postlink optimizer, F–1
profiling, 8–29 -om option (cc), 10–4
omp barrier directive, 13–6
–omp option (cc), 13–1
N omp parallel directive, 13–6
name resolution one processor directive, D–10
semantics, 4–5 OpenMP directive, 13–1
name space operators
cleanup, 2–26 precedence in dbx expressions,
naming conventions 5–10
shared libraries, 4–2 optimization
next command (dbx), 5–35 compilation options, 2–20, 10–2
nexti command (dbx), 5–35 improving with feedback file, 10–8,
nm (object file tool), 2–24 F–2, F–4
nm command, 2–24 post linking, 10–6, F–1
-noaccuracy_sensitive option (cc) profile-directed, 10–8, F–2
( See -fp_reorder option ) techniques, 10–1
use of -O option (cc), 10–2
when profiling, 8–4
O
with -om and cord, F–1
-O option (cc), 2–20, 8–4, 10–2, 10–4 with spike, 10–6
shared library problems, 4–31 optimize directive
use to avoid lint messages, 6–4 pragma optimize directive, 3–25
object file options, cc compiler, 2–12
determining file type, 2–25 output errors
determining section sizes, 2–25 using dbx to isolate, 5–5
disassembling into machine code,
2–26 P
dumping selected parts of, 2–24
listing symbol table information, -p option (cc), 8–11, 8–16
2–24 pack directive
object file tools, 2–23 pragma pack directive, 3–27
dis, 2–26 parallel directive, D–6
file, 2–25 parallel processing
nm, 2–24 OpenMP directives, 13–1
odump, 2–24 pre-OpenMP style, D–1
size, 2–25 parameter
odump (object file tool), 2–24 ( See attribute )
odump command, A–6 patch command (dbx), 5–38
pdsc.h header file, 11–3
Index–11
performance member_alignment, 3–19
profiling to improve, 8–1 message, 3–20
pfor directive, D–8 omp barrier, 13–6
-pg option (cc), 8–5, 8–10 omp parallel, 13–6
pipes, 1–7 one processor, D–10
pixie, 8–1, 8–11, 8–18, 8–24, 9–2, optimize, 3–25
10–8, F–2 pack, 3–27
( See also profiling ) parallel, D–6
-pixstats option (prof), 8–20 pfor, D–8
playback input command (dbx), 5–51 pointer_size, 3–28
playback output command (dbx), 5–53 psection, D–9
pointer size section, D–9
conversion, A–1 synchronize, D–10
pointer_size directive threadprivate, 13–7
pragma pointer_size directive, 3–28 use_linkage, 3–29
pointers weak, 3–30
32-bit, A–2 predefined variables
compound, A–1 in dbx, 5–17
long, A–1 -preempt_module option (cc), 10–4
reducing memory use for pointers -preempt_symbol option (cc), 10–4
(-xtaso), 10–19 preprocessor, C
short, A–1 ( See C preprocessor )
simple, A–1 print command (dbx), 5–47
portability printregs command (dbx), 5–48
bit fields, 6–11 procedure calls
external names, 6–11 handling efficiently, 10–12
standards, 1–2 procedure inlining
POSIX standards compilation optimizations, 10–2
application development -D_INLINE_INTRINSICS option
considerations, 1–2 (cc), 10–13
poster prof, 8–1, 8–12, 8–16, 8–18
( See event poster (EVM) ) ( See also profiling )
pragma PROFFLAGS
assert directive, 3–2 environment variable, 8–30
critical, D–9 profiling, 8–1
enter gate, D–10 CPU-time profiling with call-graph,
environment, 3–6 8–5
exit gate, D–10 CPU-time/event profiling for source
extern_model directive, 3–7 lines and instructions, 8–11
extern_prefix, 3–11 feedback files for optimization,
function, 3–14 10–8, F–2, F–4
inline, 3–13 -g option (cc), 8–4
intrinsic, 3–14 gprof, 8–5, 8–10
linkage, 3–16 hiprof, 8–5, 8–11, 8–15, 9–2
Index–12
instructions and source lines, 8–11 verifying significance of test cases,
limiting display by line, 8–26 8–23
limiting display information, 8–24 program checking
manual design and code C programs, 6–1
optimizations, 8–4 program installation tools, 1–6
memory leaks, 8–21 programming languages supported by
merging data files, 8–27, 10–10, Tru64 UNIX, 1–4
F–4 -protect_headers option, A–10
minimizing system resource usage, protect_headers_setup script, A–10
8–20 psection directive, D–9
moncontrol routine, 8–31
monitor_signal routine, 8–31 Q
monstartup routine, 8–30
multithreaded applications, 8–29 question mark (?)
-O option (cc), 8–4 search command in dbx, 5–31
-p option (cc), 8–11, 8–16 quickstart
PC sampling with hiprof, 8–15 reducing shared library load time,
-pg option (cc), 8–5, 8–10 10–6
pixie, 8–11, 8–18, 8–24, 9–2, troubleshooting
10–8, F–2 fixso, 4–14
prof, 8–12, 8–16, 8–18 manually, 4–12
profile-directed optimization, 10–8, using, 4–9
F–2, F–4 quit command (dbx), 5–9
profile-directed reordering with
cord, F–4 R
sample program, 8–2
selecting information to display, -r option (dbx), 5–8
8–24 RCS code management system, 1–5
shared library, 8–5, 8–26 record input command (dbx), 5–51
source lines and instructions, 8–11 record output command (dbx), 5–53
spike, 10–8 registers
-testcoverage option (pixie), 8–24 displaying values in dbx, 5–48
Third Degree, 7–1, 8–21, 9–2 rerun command (dbx), 5–33
uprofile, 8–11 resolution of symbols
using Atom tools, 9–1 shared libraries, 4–3
return command (dbx), 5–36
using heap memory analyzer, 8–21
routines
using monitor routines, 8–30
calling under dbx control, 5–39
using optimization options when,
run command (dbx), 5–33
8–4
run time
using system monitors, 8–21
build options that affect run time,
10–2
Index–13
coding guidelines for improving, major version, 4–21
10–13 minor version, 4–21
run-time errors mmap system call, 4–17
using dbx to isolate, 5–4 multiple version dependencies,
4–23
S naming convention, 4–2
overview, 4–2
SCCS (Source Code Control System), partial version, 4–22
1–5 performance considerations, 10–6
scope, 5–1 search path, 4–4
( See also activation levels ) specifying the location for core
determining activation levels, 5–3 dumps, 5–26
determining scope of variables, symbol resolution, 4–3
5–43 turning off, 4–7
specifying scope of dbx variables, version identifier, 4–19
5–9 versioning, 4–17
search commands in dbx (/ and ?), shared library
5–31 profiling, 8–5, 8–26
search order shared library versioning
linker libraries, 2–21 defined, 4–18
search path shared memory
limiting, 4–7 ( See System V IPC )
loader, 4–4 shared object, 4–9
shared libraries, 4–4 short pointer, A–1
section directive, D–9 signals, 1–7
secure programs, 1–4 stopping at in dbx, 5–46
semantics signed variables
name resolution, 4–5 effect on performance, 10–18
semaphores simple pointer, A–1
( See System V IPC ) size (object file tool), 2–25
set command (dbx), 5–15 slash (/)
setenv command (dbx), 5–40 search command in dbx, 5–31
effect on debugger, 5–13, 5–15 SMP
setld utility, 1–6 decomposition support in KAP,
sh command (dbx), 5–27 10–12
shared libraries sockets, 1–7
advantages, 4–1 software development tools (Tru64
applications that cannot use, 4–7 UNIX), 1–4
backwards compatibility, 4–18 source code
binary incompatibility, 4–18 checking with lint, 6–1
creating, 4–8 listing in dbx, 5–30
debugging programs using, 4–15 searching in dbx, 5–31
displaying in dbx, 5–26 source code compatibility
linking with a C program, 4–7 in System V habitat, B–1
Index–14
Source Code Control System pragma member_alignment
SCCS, 1–5 directive, 3–19
source command (dbx), 5–51 structured exception handling, 11–5
source directories structures
specifying in dbx, 5–27 checking performed by lint, 6–5
source files subscriber
controlling access to, 1–5 ( See event subscriber (EVM) )
specifying in dbx, 5–30 suffixes, file name
source line and instruction profiling, for programming language files,
8–11 2–3
-speculate option (cc), 10–3 symbol names
-spike option (cc), 10–4 completing using Ctrl/Z in dbx,
postlink optimizer, 10–6 5–15
spike command, 10–6, 10–8 symbol table
-spike option (cc), 10–6 ANSI name space cleanup, 2–27
-spike option (cc), 10–8 listing, 2–24
stack trace symbol, strong, 2–27
obtaining in dbx, 5–28 symbol, weak, 2–27
using to identify activation level, symbols
5–3, 5–28 binding, 4–30
standards, 1–2 name resolution semantics, 4–5
( See also X/Open standards ) options for handling unresolved
programming considerations, 1–2 symbols, 4–6
startup time resolution, 4–5
decreasing, 10–6 resolving in shared libraries, 4–3
static subsystem search path, 4–4
defined, C–2 symmetrical multiprocessing
status command (dbx), 5–24 ( See SMP )
stdump (object file tool), 2–27 synchronize directive, D–10
step command (dbx), 5–35 sysconfig command, C–1, C–27
stepi command (dbx), 5–35 sysconfigtab database, C–2
stop command (dbx), 5–41 system calls
$stop_on_exec variable (dbx), 5–42 differences in System V habitat,
stopi command (dbx), 5–41 B–1
storage class modifier system libraries, 4–1
_ _align, 2–8 System V habitat, B–1
STREAMS, 1–7 compiling and linking applications
strings command, 2–24 in, B–1
strong symbol, 2–27 summary of system calls, B–3
structure using cc command, B–1
member alignment, 2–5 using ld command, B–1
structure alignment System V IPC, 1–7
Index–15
T tstack command (dbx), 5–28, 5–57
-tune option (cc), 10–4
-taso option type casts
cc command, A–4 checking performed by lint, 6–6
effect of -T and -D options, A–6 when to avoid, 10–19
templates (EVM) type declarations
( See event templates ) displaying in dbx, 5–33
termination handler
how to code, 11–12
-testcoverage option (pixie), 8–24 U
text segment
unalias command (dbx), 5–23
effect of -taso option, A–6
unaligned data
Third Degree, 7–1, 8–1, 8–21, 9–2
avoiding, 10–16
( See also profiling ) unions
Thread Independent Services, 12–6
checking performed by lint, 6–5
thread-safe code
unresolved symbols
how to write, 12–5
options to ld command, 4–6
thread-safe routine
shared libraries, 4–3
characteristics, 12–3
-unroll option (cc), 10–4
threadprivate directive, 13–7
unset command (dbx), 5–15
threads, 1–7, 12–1
unsigned variables
debugging multithreaded
effect on performance, 10–18
applications, 5–57
up command (dbx), 5–29
direct I/O use, 10–15
-update option (pixie), 10–8, F–2
profiling multithreaded
-update option (prof), 10–10, F–4
applications, 8–29
uprofile, 8–1, 8–11
Visual Threads, 5–1
( See also profiling )
tlist command (dbx), 5–57
use command (dbx), 5–27
tools
use_linkage directive
major tools for software
pragma use_linkage directive, 3–29
development, 1–4 /usr/shlib directory
-T option
shared libraries, 4–2
use with -taso option, A–6
trace command (dbx), 5–43
tracei command (dbx), 5–43 V
truncated address support option,
variable data types (EVM), 14–16
A–2, A–4
variables, 5–1
( See also -taso option )
( See also environment
trusted programs, 1–4
variables )
try...except statement
assigning values to, 5–38
use in exception handler, 11–5
determining scope of, 5–43
try...finally statement
displaying names in dbx, 5–32
use in termination handler, 11–13
tset command (dbx), 5–57 displaying type declarations, 5–33
Index–16
obtaining values within activation whatis command (dbx), 5–33
levels, 5–49 when command (dbx), 5–45
predefined variables in dbx, 5–17 where command (dbx), 5–28
tracing, 5–43 whereis command (dbx), 5–32
variables, signed or unsigned which command (dbx), 5–32
effect on performance, 10–18
versioning
shared libraries, 4–17
X
Visual Threads, 5–1, 8–29 X/Open standards
application development
W considerations, 1–2
X/Open Transport Interface (XTI), 1–7
warning classes, 6–21 -xtaso option (cc), 10–19, A–2
weak directive -xtaso_short option (cc), A–2
pragma weak directive, 3–30 XTI, 1–7
weak symbol, 2–27
Index–17
How to Order Tru64 UNIX Documentation
To order Tru64 UNIX documentation in the United States and Canada, call
800-344-4825. In other countries, contact your local Compaq subsidiary.
If you have access to Compaq’s intranet, you can place an order at the following
Web site:
http://asmorder.nqo.dec.com/
If you need help deciding which documentation best meets your needs, see the Tru64
UNIX Documentation Overview, which describes the structure and organization of
the Tru64 UNIX documentation and provides brief overviews of each document.
The following table provides the order numbers for the Tru64 UNIX operating system
documentation kits. For additional information about ordering this and related
documentation, see the Documentation Overview or contact Compaq.
Tru64 UNIX
Programmer’s Guide
AA-RH9VC-TE
Compaq welcomes your comments and suggestions on this manual. Your input will help us to write
documentation that meets your needs. Please send your suggestions using one of the following methods:
• This postage-paid form
• Internet electronic mail: readers_comment@zk3.dec.com
• Fax: (603) 884-0120, Attn: UBPG Publications, ZKO3-3/Y32
If you are not using this form, please be sure you include the name of the document, the page number, and
the product name and version.
Please rate this manual:
Excellent Good Fair Poor
Accuracy (software works as manual says) 3 3 3 3
Clarity (easy to understand) 3 3 3 3
Organization (structure of subject matter) 3 3 3 3
Figures (useful) 3 3 3 3
Examples (useful) 3 3 3 3
Index (ability to find topic) 3 3 3 3
Usability (ability to access information quickly) 3 3 3 3
Please list errors you have found in this manual:
Page Description
_________ _______________________________________________________________________________________
_________ _______________________________________________________________________________________
_________ _______________________________________________________________________________________
_________ _______________________________________________________________________________________
Additional comments or suggestions to improve this manual:
___________________________________________________________________________________________________
___________________________________________________________________________________________________
___________________________________________________________________________________________________
___________________________________________________________________________________________________
What version of the software described by this manual are you using? _______________________
Name, title, department ___________________________________________________________________________
Mailing address __________________________________________________________________________________
Electronic mail ___________________________________________________________________________________
Telephone ________________________________________________________________________________________
Date _____________________________________________________________________________________________
Do Not Cut or Tear - Fold Here and Tape
NO POSTAGE
NECESSARY IF
MAILED IN THE
UNITED STATES