mirror of
https://github.com/OpenMP/Examples.git
synced 2025-04-04 05:41:33 +01:00
126 lines
6.6 KiB
TeX
126 lines
6.6 KiB
TeX
\pagebreak
|
|
\section{Structure Mapping}
|
|
\label{sec:structure_mapping}
|
|
\index{mapping!structure}
|
|
|
|
\index{directives!begin declare target@\kcode{begin declare target}}
|
|
\index{begin declare target directive@\kcode{begin declare target} directive}
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
In the example below, only structure elements \ucode{S.a}, \ucode{S.b} and \ucode{S.p}
|
|
of the \ucode{S} structure appear in \kcode{map} clauses of a \kcode{target} construct.
|
|
Only these components have corresponding variables and storage on the device.
|
|
Hence, the large arrays, \ucode{S.buffera} and \ucode{S.bufferb}, and the \ucode{S.x} component have no storage
|
|
on the device and cannot be accessed.
|
|
|
|
Also, since the pointer member \ucode{S.p} is used in an array section of a
|
|
\kcode{map} clause, the array storage of the array section on the device,
|
|
\ucode{S.p[:N]}, is \plc{attached} to the pointer member \ucode{S.p} on the device.
|
|
Explicitly mapping the pointer member \ucode{S.p} is optional in this case.
|
|
|
|
Note: The buffer arrays and the \ucode{x} variable have been grouped together, so that
|
|
the components that will reside on the device are all together (without gaps).
|
|
This allows the runtime to optimize the transfer and the storage footprint on the device.
|
|
|
|
\cexample[5.1]{target_struct_map}{1}
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
The following example is a slight modification of the above example for
|
|
a C++ class. In the member function \ucode{SAXPY::driver}
|
|
the array section \ucode{p[:N]} is attached to the pointer member \ucode{p}
|
|
on the device.
|
|
|
|
\cppexample[5.1]{target_struct_map}{2}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
%In this example a pointer, \plc{p}, is mapped in a
|
|
%\code{target data} construct (\code{map(p)}) and remains
|
|
%persistent throughout the \code{target data} region. The address stored
|
|
%on the host is not assigned to the device pointer variable, and
|
|
%the device value is not copied back to the host at the end of the
|
|
%region (for a pointer, it is as though \code{map(alloc:p}) is effectively
|
|
%used). The array section, \plc{p[:N]}, is mapped on both \code{target}
|
|
%constructs, and the pointer \plc{p} on the device is attached at the
|
|
%beginning and detached at the end of the regions to the newly created
|
|
%array section on the device.
|
|
%
|
|
%Also, in the following example the global variable, \plc{a}, becomes
|
|
%allocated when it is first used on the device in a \code{target} region,
|
|
%and persists on the device for all target regions. The value on the
|
|
%device and host may be different, as shown by the print statements.
|
|
%The values may be made consistent with the \code{update} construct,
|
|
%as shown in the \plc{declare\_target.3.c} and \plc{declare\_target.3.f90}
|
|
%examples.
|
|
%
|
|
%\cexample{target_struct_map}{2}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
The next example shows two ways in which the structure may be
|
|
\emph{incorrectly} mapped.
|
|
|
|
In Case 1, the array section \ucode{S1.p[:N]} is first mapped in an enclosing
|
|
\kcode{target data} construct, and the \kcode{target} construct then
|
|
implicitly maps the structure \ucode{S1}. The initial map of the array section
|
|
does not map the base pointer \ucode{S1.p} -- it only maps the elements of the
|
|
array section. Furthermore, the implicit map is not sufficient to ensure
|
|
pointer attachment for the structure member \ucode{S1.p} (refer to the conditions
|
|
for pointer attachment described in Section~\ref{sec:pointer_mapping}).
|
|
Consequentially, the dereference operation \ucode{S1.p[i]} in the call to
|
|
\ucode{saxpyfun} will probably fail because \ucode{S1.p} contains a host address.
|
|
|
|
In Case 2, again an array section is mapped on an enclosing
|
|
\kcode{target data} construct. This time, the nested \kcode{target}
|
|
construct explicitly maps \ucode{S2.p}, \ucode{S2.a}, and \ucode{S2.b}. But as in
|
|
Case 1, this does not satisfy the conditions for pointer attachment since the
|
|
construct must map a list item for which \ucode{S2.p} is a base pointer, and it
|
|
must do so when the \ucode{S2.p} is already present on the device or will be
|
|
created on the device as a result of the same construct.
|
|
|
|
|
|
\cexample[5.1]{target_struct_map}{3}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
The following example correctly implements pointer attachment cases that
|
|
involve implicit structure maps.
|
|
|
|
In Case 1, members \ucode{p}, \ucode{a}, and \ucode{b} of the structure \ucode{S1}
|
|
are explicitly mapped by the \kcode{target data} construct, to avoid
|
|
mapping parts of \ucode{S1} that aren't required on the device. The mapped
|
|
\ucode{S1.p} is attached to the array section \ucode{S1.p[:N]}, and remains
|
|
attached while it exists on the device (for the duration of
|
|
\kcode{target data} region). Due to the \ucode{S1} reference inside the
|
|
nested \kcode{target} construct, the construct implicitly maps \ucode{S1} so that
|
|
the reference refers to the corresponding storage created by the enclosing
|
|
\kcode{target data} region. Note that only the members \ucode{a},
|
|
\ucode{b}, and \ucode{p} may be accessed from this storage.
|
|
|
|
In Case 2, only the storage for the array section \ucode{S2.p[:N]} is mapped
|
|
by the \kcode{target data} construct. The nested \kcode{target}
|
|
construct explicitly maps \ucode{S2.a} and \ucode{S2.b} and explicitly
|
|
maps an array section for which \ucode{S2.p} is a base pointer. This satisfies
|
|
the conditions for \ucode{S2.p} becoming an attached pointer. The array
|
|
section in this case is zero-length, but the effect would be the same if the
|
|
length was a positive integer less than or equal to \ucode{N}. There is also an
|
|
implicit map of the containing structure \ucode{S2}, again due to the reference
|
|
to \ucode{S2} inside the construct. The effect of this implicit map permits
|
|
access only to members \ucode{a}, \ucode{b}, and \ucode{p}, as for Case 1.
|
|
|
|
In Case 3, there is no \kcode{target data} construct. The \kcode{target}
|
|
construct explicitly maps \ucode{S3.a} and \ucode{S3.b} and explicitly
|
|
maps an array section for which \ucode{S3.p} is a base pointer. Again, there is
|
|
an implicit map of the structure referenced in the construct, \ucode{S3}. This
|
|
implicit map also causes \ucode{S3.p} to be implicitly mapped, because no other
|
|
part of \ucode{S3} is present prior to the construct being encountered. The
|
|
result is an attached pointer \ucode{S3.p} on the device. As for Cases 1 and 2,
|
|
this implicit map only ensures that storage for the members \ucode{a}, \ucode{b},
|
|
and \ucode{p} are accessible within the corresponding \ucode{S3} that is created
|
|
on the device.
|
|
|
|
\cexample[5.1]{target_struct_map}{4}
|
|
|