source: codes/icosagcm/trunk/src/parallel/openacc_mod.F90

Last change on this file was 1055, checked in by dubos, 4 years ago

Simplify base/field.f90 to reduce repetitive code
Generate remaining repetitive code in base/field.f90 and parallel/transfert_mpi_collectives from a template

File size: 4.2 KB
Line 
1MODULE openacc_mod
2 
3  LOGICAL,SAVE :: openacc_initialized=.FALSE.
4  !$OMP THREADPRIVATE(openacc_initialized)
5 
6  INTEGER,SAVE :: openacc_device_id=-1
7  !$OMP THREADPRIVATE(openacc_device_id)
8
9  INTERFACE set_openacc_device
10    MODULE PROCEDURE set_device_manual, set_device_mpi
11  END INTERFACE
12 
13CONTAINS
14
15#ifdef _OPENACC
16  SUBROUTINE set_device_manual()
17    USE openacc
18    IMPLICIT NONE
19   
20    CHARACTER(len=32) :: device_id_value, slurm_local_id_value
21    INTEGER :: local_id, numdev, device_id_ierr, slurm_local_id_ierr, mydev
22   
23    IF (openacc_initialized) RETURN
24   
25    ! Use user set DEVICE_ID, then slurm set SLURM_LOCAL_ID, then fallback to default value
26    CALL get_environment_variable("DEVICE_ID", value=device_id_value, status=device_id_ierr) 
27    CALL get_environment_variable("SLURM_LOCALID", value=slurm_local_id_value, status=slurm_local_id_ierr) 
28    IF (device_id_ierr == 0) then
29       READ(device_id_value,*) local_id
30       PRINT *, "setDevice : found env variable DEVICE_ID =", local_id
31    ELSE IF (slurm_local_id_ierr == 0) then
32       READ(slurm_local_id_value,*) local_id
33       PRINT *, "setDevice : found env variable SLURM_LOCALID =", local_id 
34    ELSE
35     RETURN
36    END IF
37
38    ! get the number of device on this node
39    numdev = acc_get_num_devices(ACC_DEVICE_NVIDIA)
40    WRITE( *, '("local_id=",i3," numdev=",i3)') local_id, numdev
41
42    IF (numdev < 1) then
43       PRINT *, "Error: there are no devices available on this host. ABORTING"
44       STOP
45    END IF
46
47    ! print a warning if the number of devices is less than the number of processes on this node. Having multiple processes share a devices is not recommended
48    IF (numdev == local_id) then
49       ! print warning message only once per node
50       PRINT *, "WARNING: the number of process is greater than the number of GPUs."
51       mydev = mod(local_id, numdev)
52    ELSE
53       mydev = local_id
54    END IF
55 
56    CALL acc_init(ACC_DEVICE_NVIDIA)
57    CALL acc_set_device_num(mydev,ACC_DEVICE_NVIDIA)
58    openacc_device_id = acc_get_device_num(ACC_DEVICE_NVIDIA)
59    openacc_initialized=.TRUE.
60   
61  END SUBROUTINE set_device_manual
62
63#else
64  SUBROUTINE set_device_manual()
65  IMPLICIT NONE
66     
67  END SUBROUTINE set_device_manual
68#endif
69
70#ifdef _OPENACC
71  SUBROUTINE set_device_mpi(nprocs, myrank)
72    USE iso_c_binding
73    USE openacc
74    USE mpi_mod
75    IMPLICIT NONE
76   
77    INTERFACE
78       FUNCTION gethostid() bind(C)
79         USE iso_c_binding
80         INTEGER(C_INT) :: gethostid
81       END FUNCTION gethostid
82    END INTERFACE
83 
84    INTEGER, INTENT(in) :: nprocs, myrank
85    INTEGER :: hostids(nprocs), localprocs(nprocs)
86    INTEGER :: hostid, ierr, numdev, mydev, i, numlocal
87
88    IF (openacc_initialized) RETURN
89
90    ! get the hostids so we can determine what other processes are on this node
91    hostid = gethostid()
92    CALL mpi_allgather(hostid,1,MPI_INTEGER,hostids,1,MPI_INTEGER, MPI_COMM_WORLD, ierr)
93
94    ! determine which processors are on this node
95    numlocal = 0
96    localprocs(:) = 0
97    DO i = 1, nprocs
98       IF (hostid == hostids(i)) THEN
99          localprocs(i) = numlocal
100          numlocal = numlocal + 1
101       END IF
102    END DO
103
104    ! get the number of device on this node
105    numdev = acc_get_num_devices(ACC_DEVICE_NVIDIA)
106
107    IF (numdev < 1) THEN
108      PRINT *, "Error: there are no devices available on this host. ABORTING", myrank
109      STOP
110    END IF
111
112    ! print a warning if the number of devices is less than the number of processes on this node. Having multiple processes share a devices is not recommended
113    IF (numdev < numlocal) THEN
114       IF (localprocs(myrank+1) == 1) THEN
115          ! print warning message only once per node
116          PRINT *, "WARNING: the number of process is greater than the number of GPUs.", myrank
117       END IF
118       mydev = mod(localprocs(myrank+1), numdev)
119    ELSE
120       mydev = localprocs(myrank+1)
121    END IF
122
123    CALL acc_set_device_num(mydev,ACC_DEVICE_NVIDIA)
124    CALL acc_init(ACC_DEVICE_NVIDIA)
125    openacc_device_id = acc_get_device_num(ACC_DEVICE_NVIDIA)
126    openacc_initialized=.TRUE.
127
128  END SUBROUTINE set_device_mpi
129
130#else
131
132  SUBROUTINE set_device_mpi(nprocs, myrank)
133  IMPLICIT NONE
134    INTEGER, INTENT(in) :: nprocs, myrank
135  END SUBROUTINE set_device_mpi
136
137#endif 
138
139END MODULE openacc_mod
Note: See TracBrowser for help on using the repository browser.