-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmpigenesis.py
More file actions
207 lines (186 loc) · 7.27 KB
/
Copy pathmpigenesis.py
File metadata and controls
207 lines (186 loc) · 7.27 KB
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
import subprocess
from subprocess import Popen
import sys
import os
import shutil
import time
print("---------------- MPI GENESIS ------------------")
usage = "USAGE : \n"\
"\t python mpigenesis.py \n" \
"\t\t -c, --mpi_command MPI_COMMAND (mpi command to run e.g. \"mpirun -np 1\")\n"\
"\t\t -p, --num_mpi NUM_MPI (total number of MPI cores available)\n"\
"\t\t -t, --num_threads NUM_THREADS (Number of OMP threads)\n" \
"\t\t -i, --inputs GENESIS_INPUT_FILES_PATH (file containing the path to the genesis inputs files to run)\n" \
"\t\t -o, --outputs GENESIS_LOG_FILES_PATH (file containing the path to the output log files to use)\n" \
"\t\t -e, --executable GENESIS_EXECUTABLE_PATH (path to genesis executable e.g. /path/to/atdyn)\n" \
"\t\t [-a, --mpi_argument MPI_ARGUMENT ] (Additional arguments to pass to the MPI command)]\n" \
"\t\t [-r, --rankdir RANK_DIRECTORY ] (If set, use rankfiles to attribute each run to a core)\n" \
"\t\t [-cn, --num_core_per_node NUM_CORE_PER_NODE ] (if rankdir is set, defines the number of cores per node)\n" \
"\t\t [-sn, --num_socket_per_node NUM_SOCKET_PER_NODE ] (if rankdir is set, defines the number of sockets per node)\n" \
"\t\t [-n, --num_node NUM_NODE ] (if rankdir is set, defines the number of nodes) \n" \
"\t\t [-l, --localhost ] (If set, use localhost instead of relative host)\n"\
"\t\t [-f, --first_index FIRST_INDEX] (If set, will skip all the inputs until FIRST_INDEX. 1 start at the first input file)\n"\
"\t\t [-l, --last_index LAST_INDEX] (If set, will skip all the inputs after LAST_INDEX. -1 ends et the last input file)\n"\
"\n\t\t -h, --help (Print this usage message)\n"
mpi_command = ""
num_mpi = 1
num_threads = 1
inputs_path = ""
outputs_path=""
executable=""
mpi_argument=None
localhost=False
use_rankfiles= False
rankdir = ""
num_core_per_node = 1
num_socket_per_node = 1
num_node = 1
first_index = 1
last_index = -1
for i in range(1, len(sys.argv)):
if sys.argv[i] == "-h" or sys.argv[i] == "--help":
print(usage)
exit(0)
if sys.argv[i] == "-c" or sys.argv[i] == "--mpi_command":
mpi_command = sys.argv[i+1]
if sys.argv[i] == "-p" or sys.argv[i] == "--num_mpi":
num_mpi = int(sys.argv[i+1])
elif sys.argv[i] == "-t" or sys.argv[i] == "--num_threads":
num_threads = int(sys.argv[i+1])
elif sys.argv[i] == "-i" or sys.argv[i] == "--inputs":
inputs_path = sys.argv[i+1]
elif sys.argv[i] == "-o" or sys.argv[i] == "--outputs":
outputs_path = sys.argv[i+1]
elif sys.argv[i] == "-e" or sys.argv[i] == "--executable":
executable = sys.argv[i+1]
elif sys.argv[i] == "-l" or sys.argv[i] == "--localhost":
localhost = True
elif sys.argv[i] == "-r" or sys.argv[i] == "--rankdir":
rankdir = sys.argv[i + 1]
use_rankfiles= True
elif sys.argv[i] == "-a" or sys.argv[i] == "--mpi_argument":
mpi_argument = sys.argv[i+1]
elif sys.argv[i] == "-cn" or sys.argv[i] == "--num_core_per_node":
num_core_per_node = int(sys.argv[i+1])
elif sys.argv[i] == "-sn" or sys.argv[i] == "--num_socket_per_node":
num_socket_per_node = int(sys.argv[i+1])
elif sys.argv[i] == "-n" or sys.argv[i] == "--num_node":
num_node = int(sys.argv[i + 1])
elif sys.argv[i] == "-f" or sys.argv[i] == "--first_index":
first_index = int(sys.argv[i + 1])
elif sys.argv[i] == "-l" or sys.argv[i] == "--last_index":
last_index = int(sys.argv[i + 1])
print("Parameters : ")
print("\t mpi_command -> %s"%mpi_command)
print("\t num_mpi -> %s"%num_mpi)
print("\t num_threads -> %s"%num_threads)
print("\t inputs -> %s"%inputs_path)
print("\t outputs -> %s"%outputs_path)
print("\t executable -> %s"%executable)
print("\t first_index -> %i"%first_index)
print("\t last_index -> %i"%last_index)
if mpi_argument is not None:
print("\t mpi_argument -> %s" % mpi_argument )
if use_rankfiles :
print("\t rankdir -> %s" % rankdir)
print("\t num_node -> %s" % num_node)
print("\t num_core_per_node -> %s" % num_core_per_node)
print("\t num_socket_per_node -> %s" % num_socket_per_node)
print("\t localhost -> %s"%str(localhost))
#Read inputs/ outputs
inputs = []
with open(inputs_path,"r") as f:
for l in f:
inputs.append(l.strip())
outputs = []
with open(outputs_path,"r") as f:
for l in f:
outputs.append(l.strip())
num_run = len(inputs)
if len(outputs) != num_run:
raise RuntimeError("Error: number of inputs and outputs differs : %i != %i"%(num_run, len(outputs)))
if last_index != -1:
num_run = last_index
num_core_per_socket = num_core_per_node//num_socket_per_node
if use_rankfiles:
# Clean and rankfile dir
if os.path.exists(rankdir) and len(rankdir):
if os.path.isdir(rankdir):
if os.path.islink(rankdir):
os.remove(rankdir)
else:
shutil.rmtree(rankdir)
else:
os.remove(rankdir)
os.makedirs(rankdir)
# create rank files
rankfiles = []
for i in range(num_mpi):
A = int( i/num_core_per_node )
j = int( i%num_core_per_node)
B= int(j/num_core_per_socket)
C= int(j%24)
if localhost:
rank = "rank 0=localhost slot=%i:%i"%(B,C)
else:
rank = "rank 0=+n%i slot=%i:%i"%(A,B,C)
rf = os.path.join(rankdir,"rank_file_%s"%str(i+1).zfill(6))
with open(rf, "w") as f:
f.write(rank)
rankfiles.append(rf)
# prepare env
num_complete = 0
launch_index = first_index -1
env = os.environ
env["OMP_NUM_THREADS"] = str(num_threads)
process = [None for i in range(num_mpi)]
status = [0 for i in range(num_mpi)]
if mpi_argument is None:
mpi_argument = ""
# utils functions
def check_complete():
complete = 0
for i in range(num_mpi):
p = process[i]
if isinstance(p, subprocess.Popen):
stat = p.poll()
if stat is not None:
if stat != status[i]:
status[i] = stat
complete +=1
if stat != 0 :
print("Warning : one task returned a non-zero exit")
else:
status[i] = stat
return complete
def get_free_slot():
for i in range(num_mpi):
if status[i] is not None:
return i
return -1
def print_load():
print("Task completed : %i / %i"%(num_complete, num_run))
print_load()
while (1):
new = check_complete()
num_complete += new
if (num_complete == num_run):
break
if new !=0 :
print_load()
slot = get_free_slot()
if slot == -1 :
time.sleep(1)
else:
if launch_index < num_run:
if use_rankfiles :
rank_command = "--rankfile %s"%rankfiles[slot]
else:
rank_command = ""
cmd = "%s %s %s %s %s > %s"\
% (mpi_command, rank_command, mpi_argument, executable, inputs[launch_index], outputs[launch_index])
print(cmd)
p = Popen(cmd, env=env, shell=True, cwd=os.getcwd())
launch_index+=1
process[slot] = p
print("All task completed")