Jump to content United States-English
HP.com Home Products and Services Support and Drivers Solutions How to Buy
» Contact HP
More options
HP.com home
Parallel Programming Guide for HP-UX Systems > Chapter 7 Memory classes

Memory class assignments

» 

Technical documentation

Complete book in PDF
» Feedback
Content starts here

 » Table of Contents

 » Glossary

In Fortran, compiler directives are used to assign memory classes to data items. In C and C++, memory classes are assigned through the use of syntax extensions, which are defined in the header file
/usr/include/spp_prog_model.h
. This file must be included in any C or C++ program that uses memory classes. In C++, you can also use operator new to assign memory classes.

  • The Fortran memory class declarations must appear with other specification statements; they cannot appear within executable statements.

  • In C and C++, parallel storage class extensions are used, so memory classes are assigned in variable declarations.

On a single-node system, HP compilers provide mechanisms for statically assigning memory classes. This chapter discusses these memory class assignments.

The form of the directives and pragmas associated with is shown in
Table 7-1 “Form of memory class directives and variable declarations”.

Table 7-1 Form of memory class directives and variable declarations

LanguageForm
Fortran

C$DIR memory_class_name(namelist)

C/C++

#include <spp_prog_model.h>

.

.

.

[storage_class_specifier] memory_class_name type_specifier namelist

 

where (for Fortran)

memory_class_name

can be THREAD_PRIVATE, or NODE_PRIVATE

namelist

is a comma-separated list of variables, arrays, and/or COMMON block names to be assigned the class memory_class_name. COMMON block names must be enclosed in slashes (/), and only entire COMMON blocks can be assigned a class. This means arrays and variables in namelist must not also appear in a COMMON block and must not be equivalenced to data objects in COMMON blocks.

where (for C)

storage_class_specifier

specifies a nonautomatic storage class

memory_class_name

is the desired memory class (thread_private, node_private)

type_specifier

is a C or C++ data type (int, float, etc.)

namelist

is a comma-separated list of variables and/or arrays of type type_specifier

C and C++ data objects

In C and C++, data objects that are assigned a memory class must have static storage duration. This means that if the object is declared within a function, it must have the storage class extern or static. If such an object is not given one of these storage classes, its storage class defaults to automatic and it is allocated on the stack. Stack-based objects cannot be assigned a memory class; attempting to do so results in a compile-time error.

Data objects declared at file scope and assigned a memory class need not specify a storage class.

All C and C++ code examples presented in this chapter assume that the following line appears above the code presented:

   #include <spp_prog_model.h>

This header file maps user symbols to the implementation reserved space.

If operator new is used, it is also assumed that the line below appears above the code:

   #include <new.h>

If you assign a memory class to a C or C++ structure, all structure members must be of the same class.

Once a data item is assigned a memory class, the class cannot be changed.

Static assignments

Static memory class assignments are physically located with variable type declarations in the source. Static memory classes are typically used with data objects that are accessed with equal frequency by all threads. These include objects of the thread_private and node_private classes. Static assignments for all classes are explained in the subsections that follow.

thread_private

Because thread_private variables are replicated for every thread, static declarations make the most sense for them.

Example 7-1 thread_private

In Fortran, the thread_private memory class is assigned using the THREAD_PRIVATE compiler directive, as shown in the following example:

      REAL*8 TPX(1000)
REAL*8 TPY(1000)
REAL*8 TPZ(1000), X, Y
COMMON /BLK1/ TPZ, X, Y
C$DIR THREAD_PRIVATE(TPX, TPY, /BLK1/)

Each array declared here is 8000 bytes in size, and each scalar variable is 8 bytes, for a total of 24,016 bytes of data. The entire COMMON block BLK1 is placed in thread_private memory along with TPX and TPY. All memory space is replicated for each thread in hypernode-local physical memory.

Example 7-2 thread_private

The following C/C++ example demonstrates several ways to declare thread_private storage. The data objects declared here are not scoped analogously to those declared in the Fortran example:

/* tpa is global: */
thread_private double tpa[1000];
func() {
/* tpb is local to func: */
static thread_private double tpb[1000];
/* tpc, a and b are declared elsewhere: */
extern thread_private double tpc[1000],a,b;
.
.
.

The C/C++ double data type provides the same precision as Fortran’s REAL*8. The thread_private data declared here occupies the same amount of memory as that declared in the Fortran example. tpa is available to all functions lexically following it in the file. tpb is local to func and inaccessible to other functions. tpc, a, and b are declared at filescope in another file that is linked with this one.

Assume a Fortran or C program containing the appropriate example is running on a 4-hypernode subcomplex with 16 processors per hypernode and the thread_private memory is allocated from node_private memory (see the mpa(1) man page). Each data item requires 16 virtual addresses, for a total of 384,256 bytes of virtual space. These virtual addresses map to 16 physical addresses per hypernode, or 64 total physical addresses per data item, requiring a total of 1,537,024 (64 x 24016) bytes of physical memory.

Example 7-3 thread_private COMMON blocks in parallel subroutines

Data local to a procedure that is called in parallel is effectively private because storage for it is allocated on the thread’s private stack. However, if the data is in a Fortran COMMON block (or if it appears in a DATA or SAVE statement), it is not stored on the stack. Parallel accesses to such nonprivate data must be synchronized if it is assigned a shared class. Additionally, if the parallel copies of the procedure do not need to share the data, it can be assigned a private class.

Consider the following Fortran example:

      INTEGER A(1000,1000)
.
.
.
C$DIR LOOP_PARALLEL(THREADS)
DO I = 1, N
CALL PARCOM(A(1,I))
.
.
.
ENDDO
SUBROUTINE PARCOM(A)
INTEGER A(*)
INTEGER C(1000), D(1000)
COMMON /BLK1/ C, D
C$DIR THREAD_PRIVATE(/BLK1/)
INTEGER TEMP1, TEMP2
D(1:1000) = ...
.
.
.
CALL PARCOM2(A, JTA)
.
.
.
END

SUBROUTINE PARCOM2(B,JTA)
INTEGER B(*), JTA
INTEGER C(1000), D(1000)
COMMON /BLK1/ C, D
C$DIR THREAD_PRIVATE(/BLK1/)
DO J = 1, 1000
C(J) = D(J) * B(J)
ENDDO
END
.
.
.

In this example, COMMON block BLK1 is declared THREAD_PRIVATE, so every parallel instance of PARCOM gets its own copy of the arrays C and D.

Because this code is already thread-parallel when the COMMON block is defined, no further parallelism is possible, and BLK1 is therefore suitable for use anywhere in PARCOM. The local variables TEMP1 and TEMP2 are allocated on the stack, so each thread effectively has private copies of them.

node_private

Because the space for node_private variables is physically replicated, static declarations make the most sense for them.

In Fortran, the node_private memory class is assigned using the NODE_PRIVATE compiler directive, as shown in the following example:

      REAL*8 XNP(1000)
REAL*8 YNP(1000)
REAL*8 ZNP(1000), X, Y
COMMON /BLK1/ ZNP, X, Y
C$DIR NODE_PRIVATE(XNP, YNP, /BLK1/)

Again, the data requires 24,016 bytes. The contents of BLK1 are placed in node_private memory along with XNP and YNP. Space for each data item is replicated once per hypernode in hypernode-local physical memory. The same virtual address is used by each thread to access its hypernode’s copy of a data item.

node_private variables and arrays can be initialized in Fortran DATA statements.

Example 7-4 node_private

The following example shows several ways to declare

node_private data objects in C and C++:

/* npa is global: */
node_private double npa[1000];
func() {
/* npb is local to func: */
static node_private double npb[1000];
/* npc, a and b are declared elsewhere: */
extern node_private double npc[1000],a,b;
.
.
.

The node_private data declared here occupies the same amount of memory as that declared in the Fortran example. Scoping rules for this data are similar to those given for the thread_private C/C++ example.

Printable version
Privacy statement Using this site means you accept its terms Feedback to webmaster
© Hewlett-Packard Development Company, L.P.