-
Notifications
You must be signed in to change notification settings - Fork 0
/
hello_jsrun.cu
188 lines (152 loc) · 4.94 KB
/
hello_jsrun.cu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/**********************************************************
"Hello World"-type program to test different jsrun layouts.
Written by Tom Papatheodore
**********************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <mpi.h>
#include <sched.h>
#include <nvml.h>
#include <omp.h>
int main(int argc, char *argv[]){
MPI_Init(&argc, &argv);
int size;
MPI_Comm_size(MPI_COMM_WORLD, &size);
int rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
char name[MPI_MAX_PROCESSOR_NAME];
int resultlength;
MPI_Get_processor_name(name, &resultlength);
cudaError_t cuErr;
// Find how many GPUs CUDA runtime says are available
int num_devices = 0;
cuErr = cudaGetDeviceCount(&num_devices);
// Set output based on command line argument
// => verbose shows BusID and UUID for GPUs
char output_flag[64];
strcpy(output_flag, "not_verbose");
if(argc > 1){
if(strlen(argv[1]) >= sizeof(output_flag)){
printf("Argument too long: %s\n", argv[1]);
exit(0);
}
else{
strcpy(output_flag, argv[1]);
}
}
int hwthread;
int num_threads = 0;
int thread_id = 0;
#pragma omp parallel default(shared)
{
num_threads = omp_get_num_threads();
}
if(rank == 0){
printf("\n---------- MPI Ranks: %d, OpenMP Threads: %d, GPUs per Resource Set: %d ----------\n", size, num_threads, num_devices);
}
if(num_devices == 0){
#pragma omp parallel default(shared) private(hwthread, thread_id)
{
thread_id = omp_get_thread_num();
hwthread = sched_getcpu();
printf("MPI Rank %03d of %03d on HWThread %03d of Node %s, OMP_threadID %d of %d\n", rank, size, hwthread, name, thread_id, num_threads);
}
}
else{
// NVML is needed to query the UUID of GPUs, which
// allows us to check which GPU is actually being used
// by each MPI rank
nvmlReturn_t result;
result = nvmlInit();
if(NVML_SUCCESS != result){
printf("Failed to initialize NVML: %s\n", nvmlErrorString(result));
exit(0);
}
char uuid[NVML_DEVICE_UUID_BUFFER_SIZE];
char busid[64];
int gpu_id;
char uuid_list[1024] = "";
char busid_list[1024] = "";
char rt_gpu_id_list[1024] = "";
char gpu_id_list[1024] = "";
char c_i[12] = "";
char c_gpu_id[12] = "";
// Loop over the GPUs available to each MPI rank
for(int i=0; i<num_devices; i++){
cuErr = cudaSetDevice(i);
if(cudaSuccess != cuErr){
printf("CUDA Error - cudaSetDevice: %s/n", cudaGetErrorString(cuErr));
exit(0);
}
// Get the PCIBusId for each GPU and use it to query for UUID
cuErr = cudaDeviceGetPCIBusId(busid, 64, i);
if(cudaSuccess != cuErr){
printf("CUDA Error - cudaDeviceGetPCIBusId: %s/n", cudaGetErrorString(cuErr));
exit(0);
}
// Get UUID for the device based on busid
nvmlDevice_t device;
result = nvmlDeviceGetHandleByPciBusId(busid, &device);
if(NVML_SUCCESS != result){
printf("nvmlDeviceGetHandleByPciBusId Failed: %s\n", nvmlErrorString(result));
exit(0);
}
result = nvmlDeviceGetUUID(device, uuid, NVML_DEVICE_UUID_BUFFER_SIZE);
if(NVML_SUCCESS != result){
printf("nvmlDeviceGetUUID Failed: %s\n", nvmlErrorString(result));
exit(0);
}
// Map DomainID and BusID to node-local GPU ID
if(strcmp(busid, "0004:04:00.0") == 0){
gpu_id = 0;
}else if(strcmp(busid, "0004:05:00.0") == 0){
gpu_id = 1;
}else if(strcmp(busid, "0004:06:00.0") == 0){
gpu_id = 2;
}else if(strcmp(busid, "0035:03:00.0") == 0){
gpu_id = 3;
}else if(strcmp(busid, "0035:04:00.0") == 0){
gpu_id = 4;
}else if(strcmp(busid, "0035:05:00.0") == 0){
gpu_id = 5;
}else if(strcmp(busid, "0002:01:00.0") == 0){
gpu_id = 0;
}else if(strcmp(busid, "0003:01:00.0") == 0){
gpu_id = 1;
}else if(strcmp(busid, "0006:01:00.0") == 0){
gpu_id = 2;
}else if(strcmp(busid, "0007:01:00.0") == 0){
gpu_id = 3;
}else{
printf("The BusID (%s) did not map correctly to a GPU. Exiting...\n", busid);
exit(0);
}
// Concatenate per-MPIrank GPU info into strings for printf
sprintf(c_i, "%d", i);
sprintf(c_gpu_id, "%d", gpu_id);
strcat(rt_gpu_id_list, strcat(c_i, " "));
strcat(gpu_id_list, strcat(c_gpu_id, " "));
strcat(busid_list, strcat(busid, " "));
strncat(uuid_list, uuid, 10*sizeof(char));
strcat(uuid_list, " ");
}
#pragma omp parallel default(shared) private(hwthread, thread_id)
{
thread_id = omp_get_thread_num();
hwthread = sched_getcpu();
if(strcmp(output_flag, "verbose") == 0){
printf("MPI Rank %03d, OMP_thread %02d on HWThread %03d of Node %s - RT_GPU_id %s: GPU_id %s, BusID %s, UUID %s\n", rank, thread_id, hwthread, name, rt_gpu_id_list, gpu_id_list, busid_list, uuid_list);
}
else{
printf("MPI Rank %03d, OMP_thread %02d on HWThread %03d of Node %s - RT_GPU_id %s: GPU_id %s\n", rank, thread_id, hwthread, name, rt_gpu_id_list, gpu_id_list);
}
}
result = nvmlShutdown();
if(NVML_SUCCESS != result){
printf("NVML Failed to Shutdown: %s\n", nvmlErrorString(result));
exit(0);
}
}
MPI_Finalize();
return 0;
}