1
1
#! /usr/bin/env python3
2
2
3
+ """GCC per-function phase reorder benchmark kernel
4
+
5
+ This script serves as a layer between gcc compilation calls
6
+ (with phase reorder plugin) and several CompilerGym gcc-multienv environments.
7
+ """
8
+
3
9
import logging
4
10
import socket
5
11
from pathlib import Path
17
23
18
24
19
25
def sigterm_handler (sig , frame ):
26
+ """SystemExit exception is then caught to guarantee temporary directory removal"""
20
27
exit (1 )
21
28
22
29
@@ -26,6 +33,35 @@ def sigterm_handler(sig, frame):
26
33
27
34
class MultienvBenchKernel :
28
35
def __init__ (self , env_socket , gcc_socket ):
36
+ """
37
+ Parses command-line arguments and initializes kernel instance
38
+
39
+ Function arguments:
40
+ env_socket, gcc_socket -- UNIX datagram socket instances (not bound)
41
+
42
+ Command line arguments:
43
+ -r, --run
44
+ Arguments to pass to bench when running it
45
+
46
+ -b, --build
47
+ Additional arguments to pass to GCC
48
+
49
+ -n, --name
50
+ Name of the benchmark, impacts socket names (<name>:backend_<instance>)
51
+
52
+ -i, --instance
53
+ Instance number of benchmark, impacts socket names (<name>:backend_<instance>)
54
+
55
+ --repeats
56
+ Number of times that benchmark is run to profile for runtimes
57
+
58
+ -p, --plugin
59
+ Path to phase reorder plugin .so
60
+
61
+ Kernel expects all files required for benchmark build and run to already be placed into working dir
62
+ It also parses benchmark_info.txt file to get all possible symbol names
63
+ (used when checking for alive, but afk environments)
64
+ """
29
65
logging .debug ("KERNEL: init start" )
30
66
self .parser = argparse .ArgumentParser ()
31
67
self .parser .add_argument (
@@ -95,6 +131,10 @@ def __init__(self, env_socket, gcc_socket):
95
131
logging .debug ("KERNEL: init end" )
96
132
97
133
def final_cleanup (self , e ):
134
+ """
135
+ Function that removes working directory (only if /tmp or /run)
136
+ and prints all pass lists if exited with error or on signal
137
+ """
98
138
if isinstance (e , SystemExit ) and e .code == 1 :
99
139
print (self .active_funcs_lists , file = sys .stderr , flush = True )
100
140
if self .gcc_instance != None :
@@ -109,6 +149,10 @@ def final_cleanup(self, e):
109
149
os .unlink (self .socket_name )
110
150
111
151
def sendout_profiles (self ):
152
+ """
153
+ Send collected embeddings, size and runtime data to environments that have provided
154
+ lists before compilation start
155
+ """
112
156
for fun_name in self .active_funcs_lists :
113
157
func_env_address = (
114
158
f"\0 { self .args .bench_name } :{ fun_name } _{ self .args .instance } "
@@ -140,6 +184,9 @@ def sendout_profiles(self):
140
184
)
141
185
142
186
def get_sizes (self ):
187
+ """
188
+ Parses nm output to get symbol sizes
189
+ """
143
190
size_info = (
144
191
run (
145
192
"${AARCH_PREFIX}nm --print-size --size-sort --radix=d main.elf" ,
@@ -155,6 +202,10 @@ def get_sizes(self):
155
202
self .sizes [self .encode_fun_name (pieces [3 ])] = int (pieces [1 ])
156
203
157
204
def get_runtimes (self ):
205
+ """
206
+ Runs instrumented benchmarks, sums their runtime data using gprof
207
+ and parses its output for runtime information
208
+ """
158
209
run (
159
210
"${AARCH_PREFIX}nm --extern-only --defined-only -v --print-file-name pg_main.elf > symtab" ,
160
211
shell = True ,
@@ -201,6 +252,10 @@ def get_runtimes(self):
201
252
)
202
253
203
254
def compile_instrumented (self ):
255
+ """
256
+ Compiles benchmarks using received lists and with enabled -pg flag
257
+ (for per-function runtime profiling)
258
+ """
204
259
self .gcc_instance = Popen (
205
260
self .gprof_build_str , shell = True
206
261
) # Compile with gprof to get per-function runtime info
@@ -242,6 +297,10 @@ def compile_instrumented(self):
242
297
exit (1 )
243
298
244
299
def encode_fun_name (self , fun_name ):
300
+ """
301
+ If needed, hashes symbol name and encodes it in base64 to fit into
302
+ 108 characters socket addr length limitation
303
+ """
245
304
fun_name = fun_name .partition ("." )[0 ]
246
305
avail_length = (
247
306
107 - len (self .args .bench_name ) - len (str (self .args .instance )) - 2
@@ -255,6 +314,9 @@ def encode_fun_name(self, fun_name):
255
314
return fun_name
256
315
257
316
def validate_addr (self , parsed_addr ):
317
+ """
318
+ Checks if addres matches kernel benchmark name, instance number and symbol list
319
+ """
258
320
if parsed_addr [1 ] != self .args .bench_name :
259
321
print (
260
322
f"Got message from env with incorrect bench name. "
@@ -278,11 +340,21 @@ def validate_addr(self, parsed_addr):
278
340
exit (1 )
279
341
280
342
def add_env_to_list (self , pass_list , addr ):
343
+ """
344
+ Parses address, validates it and adds received pass list to
345
+ dictionary of lists to be used during next compilation cycle
346
+ """
281
347
parsed_addr = re .match ("\0 (.*):(.*)_(\d*)" , addr .decode ("utf-8" ))
282
348
self .validate_addr (parsed_addr )
283
349
self .active_funcs_lists [parsed_addr [2 ]] = pass_list
284
350
285
351
def gather_active_envs (self ):
352
+ """
353
+ Receives pass lists from envs and closes kernel if no active envs were detected after a minute delay
354
+
355
+ When the first list is received, sets 5 second socket timeout to
356
+ give other envs a chance to send their lists and returns after no new lists were received in this timeout
357
+ """
286
358
while True :
287
359
self .active_funcs_lists = {}
288
360
@@ -320,8 +392,10 @@ def gather_active_envs(self):
320
392
exit (0 )
321
393
322
394
def compile_for_size (self ):
395
+ """
396
+ Compiles benchmark with received lists and record embeddings
397
+ """
323
398
self .embeddings = {}
324
-
325
399
self .gcc_instance = Popen (
326
400
self .build_str , shell = True
327
401
) # Compile without gprof do all the compilation stuff
@@ -371,6 +445,11 @@ def compile_for_size(self):
371
445
exit (1 )
372
446
373
447
def kernel_loop (self ):
448
+ """
449
+ Main kernel loop, which also catches exceptions
450
+ (including SystemExit, KeyboardInterrupt and that from SIGTERM signal)
451
+ and calls final_cleanup() when exception is caught
452
+ """
374
453
try :
375
454
while True :
376
455
logging .debug ("KERNEL: compilation cucle" )
0 commit comments