- Unix Design Philosophy
- Compiling Programs
- Using the Fortran compiler
- Using the C Programming Language
- Redirecting Standard Error
- Bourne and Korn Shells
- C Shell
- Background Processing
- Background Jobs and Logout -- the "nohup" command
- Changing Priority: nice
- Monitoring Process Status
- Terminating a Process
- Obtaining Execution Times
- Using the Profiler to Determine Time Spent in SubProgram Components
- Unix Program Development Tools
- Using the make Utility
- Using the Archive Librarian
- Mixed Language Programming: Timing Portions of Fortran Code Using a C Language Function
Unix has become popular among program developers as it includes several
features which they find to be very desirable:
- Portability (Machine Independence)
- A Powerful Multi-User System
- Shell Command Interpreter
- Hierarchical File Structure
- Multi-Tasking with Background Processing Capabilities (&)
- Extensible via the C Language
- Networking Capabilities
- Security Features
- Widely Accepted
Unix Design Philosophy
To work with greatest effectiveness in the Unix programming environment,
you should be aware of some of the design characteristics
of the operating system:
- Simplicity
- Short commands: minimal typing
- "No News is Good News!"
- Modularity: Write programs so that their output can be used as
input by other programs.
- Power and Functionality: Provide a wealth of single purpose utilities.
- Confidence: You know what you are doing!
- If you erase a file, it is gone.
- If you use the name of an existing file as the target for a rename
or copy, the original file is replaced by the new file.
Compiling Programs
Compilers are available on VTAIX for Fortran
(xlf, f77, or f90 command),
the C programming language (xlc or cc command), and Pascal (xlp command).
Providing arguments are passed correctly, it is possible to write
programs which use a mixture of these languages.
Using the Fortran compiler
xlf is IBM's "eXceptionaL Fortran" compiler which is an ANSI standard
Fortran compiler with IBM extensions.
If you are using a non-AIX version of Unix, use the command
"f77" or "f90" in place of "xlf" in the examples which follow.
The Fortran compiler xlf
on VTAIX is invoked by entering the command "xlf" or "f77" followed
by compilation options and the names of the source files you wish to
compile.
Fortran source files must end in the characters
".f"; otherwise the compiler will reject the source file for ending
in an invalid suffix.
For example, to compile Fortran
source code contained in the file "prog_name.f" and create the
executable module "a.out", enter:
xlf prog_name.f
To execute this program, simply enter:
./a.out
Use the "-o" option if you wish to specify the name of the output
executable
file to be created by the compilation. For example, to assign the
name "my_prog" to the executable created by compiling prog_name.f, enter:
xlf -o my_prog prog_name.f
To execute this program, simply enter:
./my_prog
Additional options include:
- -c
- compile only (do not link)
- -C
- perform run-time checking of array bounds and character
substring expressions
- -g
- produce debug information
- -lname
- search library "name"
- -o
- name the executable module (instead of a.out)
- -O
- perform optimization
- -qsource
- produce an output source listing
For additional information about the compiler and option flags, enter:
man xlf
You can compile and link more than one file when you invoke the
Fortran complier. For example, to create an executable program called
"statsall" from the subprogram modules "statsmain.f", "means.f", and
"std.f" from within the xmp directory, enter:
xlf -o statsall statsmain.f means.f std.f
The xlf Fortran compiler on
VTAIX is an ANSI Fortran 77 compiler with IBM extensions. If you
limit yourself to using the Fortran 77 standard, you should
be able to port code to and from xlf with minimal difficulty.
Since xlf includes more extensions than VS Fortran, it is anticipated
that individuals who use IBM extensions will encounter more problems
porting xlf applications to other environments than will be
encountered in porting applications to xlf.
The RS/6000 uses double precision arithmetic in its computations:
For most applications there
is no reason to run Single Precision -- in some cases Single
Precision Programs will run slower than Double as the machine
does all of its Real computations in Double Precision and rounds
to create Single Precision numbers.
xlf uses IEEE Floating Point Representation:
This may result in different precision and ranges for numbers, for
example:
- The approximate non-zero minimum double precision number is
2.225074D-308
- The approximate absolute maximum double precision number is
1.797693D+308
- The approximate precision is 7 single precision (REAL*4) digits,
15 double precision (REAL*8), and 31 quad precision (REAL*16) digits.
xlf may treat floating point exceptions differently than
other compilers. Some notable differences include:
- Division by zero: the result is set equal to "INF" and
processing continues
- Division by infinity: the result is set equal to zero
The SAVE Statement may be required to preserve results when a
subroutine or function is reused.
The xlf Fortran compiler does not necessarily preserve
values upon exit from subroutines.
Thus it may be necessary to add SAVE statements in some or all of your
subroutines to guarantee that values will be preserved from one
invocation of the routine to the next.
To provide maximum portability among systems, it is
recommended that you use SAVE statements in your programs whenever
you wish to preserve values from one subprogram call to the next.
In the Unix environment, Fortran Unit 5 corresponds to standard input
and Unit 6 corresponds to standard output.
Redirection can be used in the standard Unix fashion to associate
files with these units.
Typically, OPEN statements are used within Fortran programs to
associate external files with other unit numbers.
By default, if no OPEN statement is used on VTAIX,
output (or input) for other unit numbers will
be written to (or read from) file
fort.#, where # is a number
corresponding to the unit used for output (or input), e.g.,
fort.1
will be used for unit 1 and
fort.27
will be used for unit 27.
If you are using another Unix system, write output to units 1 and 27 and
observe the filenames used as the defaults for these unit numbers.
If you prefer to use external commands to associate file names
with unit numbers in your Fortran code, you can use the corresponding
environmental variables or use an ln (link) command
to assign these associations for you. The syntax required is compiler
dependent and you will need to check its documentation to determine
the syntax you should use.
For example, on VTAIX, you can use the following command to
associate unit 10 with the file "my.data" in your "xyz" sub-directory:
ln -s ~/xyz/my.data fort.10
Note: if the file fort.1 already exists, it should either be removed or
moved to a new name prior to issuing the above symbolic link command.
Note: if you have already associated a file with a Fortran unit and
would like to reassign the link, use the -fs option, e.g.:
ln -fs ~/xyz/my.data fort.10
Using the C Programming Language
C programming language files which are to be compiled by the
cc command must end in the characters ".c". On VTAIX, you can also
invoke the eXceptionaL C compiler by using the xlc command.
The sample programs copied to your disk
include several
C source code files in the xmp/c subdirectory. Use the following
command to compile 2cent.c which converts a value provided in standard
input from Fahrenheit temperature to Centigrade and places the result in
standard output:
cc 2cent.c
You can execute the program by entering:
./a.out
The program waits until you enter a numeric value corresponding to
a temperature in degrees Fahrenheit. The program will compute the
corresponding value
in degrees centigrade and display it on the screen.
At this point you might be wondering why the program does not display
a prompt to indicate the type of input which it requires. Previously,
we had discussed the utility of filters, programs which accept standard
input and write to standard output. Here is another example of a filter.
This program can accept input piped from another application or pipe
output to another program. We will illustrate use of this program as a
filter in the exercises which follow.
In order to keep the files organized on your disk, let's rename the file
a.out to 2cent using the mv (move) command:
mv a.out 2cent
As you have seen in the preceding example,
cc assigns the default name "a.out" to the executable file it
creates. To assign an alternative name to the executable when the
source code is compiled, use the "-o" option of the compiler. For
example, to compile 2fahren.c and assign the name 2fahren to the
executable it creates, enter:
cc -o 2fahren 2fahren.c
Now we will use redirection to create two output files:
./2fahren > ctemp.data
53
./2fahren > second.data
19.56
Observe that the value is no longer displayed on the screen.
Use the "cat" command
to display the contents of the file "ctemp.data" and then use input
redirection to use the stored data value and display the result on the
screen:
cat ctemp.data
./2cent < ctemp.data
Observe that the value displayed by the 2cent command is the same value
you had originally input to the 2fahren command.
If you would like to add additional data to an output file, use the
append (">>") redirection symbol:
./2fahren >> ctemp.data
29
cat ctemp.data
Since both 2fahren and 2cent use standard input and standard output,
they can be used as filters to process an input data value:
./2fahren < second.data | tee ctemp.data | ./2cent ;
12
The preceding command string uses converts the data value stored in
second.data
Fahrenheit to Centigrade, pipes the output to
the "tee" command which places the result in the file ctemp.data and
in standard output where it is piped to 2fahren. The result is the same
as the value entered to the 2cent command. The converted Centigrade
temperature is found in ctemp.data. Observe that the previously stored
values in ctemp.data have been overwritten.
Note:
File my_source.c contains a C program which prompts for an
input value and then converts it from Fahrenheit to Centigrade.
You can compile and link more than one file when you invoke the
C complier. For example, to create an executable program called
"statsall" from the subprogram modules "statsmain.c", "means.c", and
"std.c" from within the xmp/c directory, enter:
cc -o statsall statsmain.c means.c std.c
Redirecting Standard Error
Error diagnostics
generated by a program are normally directed to the terminal screen
even when the standard output has been redirected to a file; however,
it is useful, at times,
to be able to write the error diagnostics to a file. This
section will show how these diagnostics can be written either to their
own file, or to the same file as standard output.
Bourne and Korn Shells
Recall that you can use the redirections symbol (>) to place program
output in a file:
./filesize > output
cat output
In a similar fashion you can redirect standard error by preceding the
redirection symbol by the number "2":
./cars 2> err
cat err
When redirecting both standard output and standard error, it is customary
to precede the standard output redirection by the number "1":
./my_prog 1> output 2> err
To send both standard output and standard error to the same file, use
&1 following the redirection symbol corresponding to
standard error:
./my_prog 1> output 2>&1
C Shell
If you are using the C Shell, use the greater than symbol
(>) to specify the file to be used for standard output and the
greater than symbol followed by an ampersand
(>&) to specify the file to be used for standard error.
For example, to send
the standard output from the program "my_prog"
to a file called "my_prog.out" and the error
diagnostics to a file called "my_prog.err", enter the following command:
./my_prog >my_prog.out >&my_prog.err
Sometimes it is desirable to include the error diagnostics in the
same file as the standard output. To write both the standard output
and error diagnostics from "my_prog" to my_prog.out", enter:
./my_prog >&my_prog.out
Background Processing
When you are busy, you may not want to wait until a command finishes
processing before you enter your next command.
You can begin a process in the background by including an
ampersand (&)
following the command; you can then continue working by entering
new commands.
For example, to compile 2cent.c in the background, enter:
cc -o 2cent 2cent.c &
ls
Background Jobs and Logout -- the "nohup" command
In the prior section, you learned how to run a job in the background
while you continued to execute other programs; however,
background processing is typically terminated when you logout.
To enable a program to continue running in the background even after
logging off, precede the command you wish to run in the background with
the command "nohup".
By default, the program output (standard output
and standard error) will be placed in the file "nohup.out" in the
working directory.
If you like, you may specify files for redirecting the output (see also
Redirecting Standard Error).
For example, to submit a background job "my_prog"
for execution, enable it to run after you logout, and to send the
standard output to file "my_prog.out" and standard error to
"my_prog.err", enter:
nohup ./my_prog 1> my_prog.out 2> my_prog.err &
The C Shell includes its own internal "nohup" command.
This internal command does not create a default "nohup.out" file for
program output; you must redirect the output to files if you wish to
have it preserved across sessions.
For example, to submit a background job "my_prog"
for execution, enable it to run after you logout, and to send the
standard output and standard error to
"my_prog.out", enter:
nohup ./my_prog >&my_prog.out &
Changing Priority: nice
If you are working on a shared system or if you are running multiple
cpu intensive jobs, you may wish to assign a lower priority to some
jobs so that time critical jobs can be done as soon as possible and
yet allow the low priority jobs to execute using the remaining cpu
cycles.
The "nice" command
is used to indicate that you would like these jobs to be "nice" relative
to the rest of the system, i.e., you would like them to be executed at a
lower priority. For example, to run "my_prog"
in the background at a lower priority, enter:
nice ./my_prog &
Typically you would also redirect the standard
output and standard error from "my_prog" to files
(see Redirecting Standard Error
if you are using the Bourne or Korn Shell; see
C Shell
if you are using the C shell).
If you might logoff prior to the job's
completion, you should precede this command with the
nohup
command.
Monitoring Process Status
You can list your current processes by entering the ps command.
If you have logged off and logged back on,
you can list the current status of your jobs by entering one of the
following commands:
ps aux | grep $USER
or
ps aux | more
The "aux" option is necessary if you have logged off and logged back
on; otherwise only the processes started during the current session
will be displayed.
If the program creates an output file, you can monitor job progress
using the tail command:
tail -f ./my_prog.out
The "-f" option continually displays the contents of the file as new
information is added and you can thus watch the output from a
background job as it is generated. You can terminate the display of
the program output by pressing <Ctrl-C> to cancel the tail command.
Terminating a Process
After you have listed the current processes, you have available the
process id numbers. You can then use the kill command with
the process id number of one of
your jobs to specify the
job you wish to cancel:
kill my_prog_process_number
The C and Korn Shells provide capabilities for changing the status of
a process. Thus it is possible to place a job which is already executing
in the foreground into the background or to bring a background job into
the interactive environment.
The shell commands "bg" and "fg" are used to move processes
to the background and foreground. To move an active job into the
background, first suspend it by pressing <Ctrl-Z> and then enter the
command "bg". To bring a background job into the foreground, use the
ps command to obtain its process control id number and then enter:
fg process_id_number
Obtaining Execution Times
The "time" command can be used to write program execution time statistics
(CPU and wall clock time) to standard error.
The system "time" command returns the following values:
- real
- elapsed clock time in seconds
- user
- user process time in seconds
- sys
- CPU time in seconds
To execute "my_prog" in the background,
to write
standard output "myprog.out", and to write any error diagnostics and
the timing statistics to "my_prog.err", enter:
time ./my_prog 1> my_prog.out 2> my_prog.err &
To write both standard output and standard error to the same file
"my_prog.out", enter:
time ./my_prog 1> my_prog.out 2>&1 &
The C Shell includes its own internal "time" command which generates
different output from that of the system "time" command. If you are
using the C Shell, you have a choice of which "time" command to use.
The internal command will be used unless you specify the path (typically
"/bin") for the system time command.
To execute "my_prog" in the background,
to write
standard output "myprog.out", and to write any error diagnostics and
the timing statistics (from the system "time" command)
to "my_prog.err", enter:
(/bin/time ./my_prog >my_prog.out) >&my_prog.err &
To write both standard output and standard error to the same file
"my_prog.out", enter:
/bin/time ./my_prog >&my_prog.out &
If you are using a system other
than VTAIX and "/bin/time" does not enable you to access the system "time"
command,
use the command "which time" to determine the directory which
contains the system "time" command. Then
substitute the result for "/bin/time" in the examples
above.
Using the Profiler to Determine Time Spent in SubProgram Components
The -O (optimize) compiler option requests that the compiler optimize
the executable code for best performance. If you are writing a program
which will be executed many times, you can sometimes obtain even
greater performance by rewriting portions of the code. The profiler
can be used to identify those portions of your code which require
the most processing time and thus suggest sections of code which might
hold the greatest promise for revision.
The profiler is easy to use: first include
the -p option when you compile your code, execute the program, and then
run the program "prof". The following example illustrates how the
profiler could be used with the sample Fortran program included in the
xmp subdirectory:
xlf -p -ostatsall statmain.f means.f std.f
./statsall
prof > prof.out
The results of the profile analysis will be placed in the file prof.out
which you can examine to observe the amount of time spent in each
of the component subprograms and library calls made by the program.
If a routine is called multiple times within your program, use "-pg"
instead of "-p" in the above example and "gprof" instead "prof".
The g profiler provides extended diagnostics which will help you
identify which calls to a subprogram were the ones which were most
time consuming.
Both profilers create large intermediate output files (may
exceed your disk quota). After you are finished your analysis, you
should delete the file mon.out (gmon.out if you are using the g
profiler). Once you are finished with the profile analysis, you should
also recompile your code without the "-p" (or "-pg") option.
Unix Program Development Tools
Some of the tools which make Unix particularly attractive to program
developers include:
- awk
- search and process patterns within files
- lint
- syntax checker for C code portability across systems
- make
- maintains programs in most current form.
- sccs
- Source Code Control System which provides management
and tracking of code or text document development.
- cpp
- performs file inclusion and macro substitution in C language
source files.
- m4
- processes files with expansion of macro definitions
- curses
- provides control of cursor positioning and window usage.
- sed
- text stream (non-interactive) editor
Using the make Utility
The make command is used in program development to simplify the
process of compilation when a program consists of several subprogram
components. Rather than recompiling every routine when the code is
changed, the make program rebuilds only those object code segments
which would be affected by the changes.
This capability becomes particularly useful when the code contains
several include files.
The following exercise illustrates use of make with a Fortran program
consisting of a main program, two subprograms, and an include file
used in the main program and one of the subprograms.
- Examine the contents of "makefile" and read the comments which
describe each of the commands contained in the file.
Note:
The indentations at the beginning of lines in a makefile must be created
by 'tab' characters and not by spaces.
- Generate and execute a program from
multiple Fortran source files:
- Edit (vi) "included"
and change the value of MVARS to 5. Repeat
step 1 above and note:
- subroutine var
was not recompiled as it is not dependent upon 'included'.
- The output now consists of 5 lines instead of just one.
The 'touch' command can be used to change the time of the last
file modification
to test that your makefile is performing as desired.
A second example makefile is provided in the file "makefile.f".
This makefile performs the same functions, but includes additional
statements to define make variables to provide a more portable file
for use with other operating systems. Simply by changing the values
of the variables "compile", "link", and "librarian" to the appropriate
commands and command options, this makefile can be used with Microsoft
Fortran as well as with Fortran compilers on other Unix systems. To
use with other Unix systems, simply change "xlf" to "f77".
The make command uses the file "makefile", "MAKEFILE", or MakeFile"
as a source file of commands used to build a program. The "-f" option
of the make command is used to specify the name of a file containing
"make" commands which is to be used to build a program. For example,
to compile and then execute the program "statsall" created by using the
commands in the file "makefile.f", enter:
make -f makefile.c
./statsall
A third example makefile is provided in the "C" subdirectory that you
copied from aixstu00. Change into this directory and enter the
following command to build and execute
a new version of the "statsall" executable
from c source code:
make -f makefile.c
./statsall
Using the Archive Librarian
The ar command is used to create and manage archive libraries. These
libraries may contain source files or compiled object code.
The command flags 'vru' can be used with the ar command to create a
new archive library or to update and replace members in an existing
library.
To create the archive library 'libstats' from
the object code files means.o and
std.o, you could use the following command:
ar vru libstats.a means.o std.o
You can then use this library with other Fortran programs by using
the -L (followed by the name of the directory containing the library)
and -l (lower case "L"
followed by the library name) options of the xlf command
when you link the compiled code components. For example, to use
the library 'libstat.a' in the current directory when you compile and
link 'statmain' to 'create 'statsall', you could use the following
command:
xlf -o statsall statmain.f -L. -lstats
The example file 'makefile.f' uses the above command to maintain the
object code for two subroutines which it requires.
A wide variety of Fortran, C, and other programming language source files
are available by
anonymous ftp
on the Internet.
If you use some of these routines
frequently, you may find it advantageous to compile and store the
compiled code in an archive library.
Note:
Archive libraries, including source code only archive libraries,
are not portable across Unix systems.
If you are using more than one Unix system, you will typically will
need to recreate archive libraries on each of the systems where you would
like to use them.
Some users of VTAIX have set permissions on their library archives to
allow others to use these libraries.
The ar command can also be used to list and extract
the members of archive libraries.
For example, to list the subroutines present in
libstats.a, enter:
ar -vt libstats.a
To extract the
object code for 'means.o' from 'libstats.a', enter:
ar -vx libstats.a means.o
To delete a library member, use the '-d' option flag of the ar command.
Mixed Language Programming: Timing Portions of Fortran Code Using a C Language Function
The examples illustrated at the end of this section include a
shell script
which can be executed under the AIX operating system to compile the
C function cclock,
compile a
Fortran program, link the two
sets of object code, and then run the resultant module.
The example files illustrated in these figures are found in
the /xmp/mixed_lang subdirectory copied to your disk with the sample
files.
The option -lc is used with the xlf command to include the
C language libraries required by the timing routine when the two programs
are linked.
As seen in this example, it is easy to combine
object code from different compilers on VTAIX. You must be careful
about passing arguments between different languages, but if this is
done correctly, all you must then do is to compile the code using
the corresponding compiler with the -c (compile only) option and
then link (xlf in the example) with the required language libraries.
On other systems, mixed language programming may not be this easy.
Additional code within the calling and called programs may be required to
properly define the languages being used or a specific nomenclature may
be require for functions which are to be called by another language; see
your system's documentation for details.
Shell Program "test.sh"
-- This shell script is used to
to compile a Fortran program which invokes a C function to obtain timing
statistics.
#!/bin/sh
# Shell script to Compile a Fortran Program which
# Invokes a C Function xlc -c cclock.c
xlf -o myprog progname.f cclock.o -lc
/bin/time ./myprog
C Function "cclock.c"
/* C function to compute elapsed CPU time using the Unix clock function */
/* This C function returns CPU utilization in milliseconds */
/* It is, however, only accurate to about 1/100 second */
/* To access from a Fortran program, use: CALL cclock(isec) */
/* where isec is INTEGER*4 */
#include <time.h>
void cclock(long int *cpu_sec)
{
*cpu_sec = clock();
}
C ---- Example Fortran Program "progname.f"
C
C This Fortran program calls the C language function to obtain
C timing statistics.
C
INTEGER*4 TIME
CALL cclock(time)
WRITE(6,*) 'CPU Time Utilization is: ',time/1E+6,' Seconds'
do 1000 i=1, 1000000
x = i
y = x * x
1000 Continue
CALL cclock(time)
WRITE(6,*) 'CPU Time Utilization is: ',time/1E+6,' Seconds'
do 2000 i=1,2400000
x = i
y = x * x
2000 Continue
CALL cclock(time)
WRITE(6,*) 'CPU Time Utilization is: ',time/1E+6,' Seconds'
CALL cclock(time)
WRITE(6,*) 'CPU Time Utilization is: ',time/1E+6,' Seconds'
END
|