1
- import sys , os , subprocess , argparse , logging , json
1
+ import sys , os , subprocess , argparse , logging , json , tempfile , multiprocessing
2
2
3
3
# Try to more extensively check the cost model figures coming out of the cost model, for every operation x type combo.
4
4
# Currently it looks at costsize costs, as those are easier to measure.
10
10
# and this to serve is to pert 8081, inside a venv with pandas
11
11
# python llvm/utils/costmodeltest.py --servellvm/utils/costmodeltest.py
12
12
13
- logging .basicConfig (stream = sys .stdout , level = logging .DEBUG , format = '' )
13
+ logging .basicConfig (stream = sys .stdout , level = logging .WARNING , format = '' )
14
14
logging .getLogger ("requests" ).setLevel (logging .WARNING )
15
15
logging .getLogger ("urllib3" ).setLevel (logging .WARNING )
16
16
@@ -19,21 +19,21 @@ def run(cmd):
19
19
cmd = cmd .split ()
20
20
return subprocess .check_output (cmd , stderr = subprocess .STDOUT ).decode ('utf-8' )
21
21
22
- def getcost (costkind , print ):
23
- text = run (f"opt { '-mtriple=' + args .mtriple if args .mtriple else '' } { '-mattr=' + args .mattr if args .mattr else '' } costtest.ll -passes=print<cost-model> -cost-kind={ costkind } -disable-output" )
22
+ def getcost (path , costkind , print ):
23
+ text = run (f"opt { '-mtriple=' + args .mtriple if args .mtriple else '' } { '-mattr=' + args .mattr if args .mattr else '' } { os . path . join ( path , ' costtest.ll' ) } -passes=print<cost-model> -cost-kind={ costkind } -disable-output" )
24
24
costpre = 'Cost Model: Found an estimated cost of '
25
25
if print :
26
26
logging .debug (text .strip ())
27
27
costs = [x for x in text .split ('\n ' ) if 'instruction: ret ' not in x ]
28
28
cost = sum ([int (x [len (costpre ):len (costpre )+ x [len (costpre ):].find (' ' )]) for x in costs if x .startswith (costpre )])
29
29
return (cost , text .strip ())
30
30
31
- def getasm (extraflags ):
31
+ def getasm (path , extraflags ):
32
32
try :
33
- run (f"llc { '-mtriple=' + args .mtriple if args .mtriple else '' } { '-mattr=' + args .mattr if args .mattr else '' } { extraflags } costtest.ll -o costtest.s" )
33
+ run (f"llc { '-mtriple=' + args .mtriple if args .mtriple else '' } { '-mattr=' + args .mattr if args .mattr else '' } { extraflags } { os . path . join ( path , ' costtest.ll' ) } -o { os . path . join ( path , ' costtest.s' ) } " )
34
34
except subprocess .CalledProcessError as e :
35
35
return ([e .output .decode ('utf-8' ).split ('\n ' )[0 ]], - 1 )
36
- with open ("costtest.s" ) as f :
36
+ with open (os . path . join ( path , "costtest.s" ) ) as f :
37
37
lines = [l .strip () for l in f ]
38
38
# This tries to remove .declarations, comments etc
39
39
lines = [l for l in lines if l [0 ] != '.' and l [0 ] != '/' and not l .startswith ('test:' )]
@@ -50,20 +50,21 @@ def getasm(extraflags):
50
50
51
51
def checkcosts (llasm ):
52
52
logging .debug (llasm )
53
- with open ("costtest.ll" , "w" ) as f :
54
- f .write (llasm )
53
+ with tempfile .TemporaryDirectory () as tmp :
54
+ with open (os .path .join (tmp , "costtest.ll" ), "w" ) as f :
55
+ f .write (llasm )
55
56
56
- lines , size = getasm ('' )
57
+ lines , size = getasm (tmp , '' )
57
58
58
- gilines , gisize = getasm ('-global-isel' )
59
+ gilines , gisize = getasm (tmp , '-global-isel' )
59
60
60
- codesize = getcost ('code-size' , True )
61
- thru = getcost ('throughput' , False )
62
- lat = getcost ('latency' , False )
63
- sizelat = getcost ('size-latency' , False )
61
+ codesize = getcost (tmp , 'code-size' , True )
62
+ thru = getcost (tmp , 'throughput' , False )
63
+ lat = getcost (tmp , 'latency' , False )
64
+ sizelat = getcost (tmp , 'size-latency' , False )
64
65
65
- logging .debug (f"cost = codesize:{ codesize [0 ]} throughput:{ thru [0 ]} lat:{ lat [0 ]} sizelat:{ sizelat [0 ]} " )
66
- return (size , gisize , [codesize , thru , lat , sizelat ], llasm , ('\n ' .join (lines )).replace ('\t ' , ' ' ), ('\n ' .join (gilines )).replace ('\t ' , ' ' ))
66
+ logging .debug (f"cost = codesize:{ codesize [0 ]} throughput:{ thru [0 ]} lat:{ lat [0 ]} sizelat:{ sizelat [0 ]} " )
67
+ return (size , gisize , [codesize , thru , lat , sizelat ], llasm , ('\n ' .join (lines )).replace ('\t ' , ' ' ), ('\n ' .join (gilines )).replace ('\t ' , ' ' ))
67
68
68
69
# TODOD:
69
70
#if args.checkopted:
@@ -191,40 +192,37 @@ def binop_variants(ty):
191
192
args = parser .parse_args ()
192
193
193
194
194
- def do (instr , variant , ty , ty2 , extrasize , data , tyoverride = None ):
195
+ def do (instr , variant , ty , ty2 , extrasize , tyoverride ):
195
196
logging .info (f"{ variant } { instr } with { ty .str ()} " )
196
197
(size , gisize , costs , ll , asm , giasm ) = checkcosts (generate (variant , instr , ty , ty2 ))
197
198
tystr = str (ty ) if not tyoverride else tyoverride
198
199
if costs [0 ][0 ] != size - extrasize :
199
200
logging .warning (f">>> { variant } { instr } with { tystr } size = { size } vs cost = { costs [0 ][0 ]} (expected extrasize={ extrasize } )" )
200
- data .append ({"instr" :instr , "ty" :tystr , "variant" :variant , "codesize" :costs [0 ][0 ], "thru" :costs [1 ][0 ], "lat" :costs [2 ][0 ], "sizelat" :costs [3 ][0 ], "size" :size , "gisize" :gisize , "extrasize" :extrasize , "asm" :asm , "giasm" :giasm , "ll" :ll , "costoutput" :costs [0 ][1 ]})
201
- logging .debug ('' )
201
+ return {"instr" :instr , "ty" :tystr , "variant" :variant , "codesize" :costs [0 ][0 ], "thru" :costs [1 ][0 ], "lat" :costs [2 ][0 ], "sizelat" :costs [3 ][0 ], "size" :size , "gisize" :gisize , "extrasize" :extrasize , "asm" :asm , "giasm" :giasm , "ll" :ll , "costoutput" :costs [0 ][1 ]}
202
202
203
203
# Operations are the ones in https://github.com/llvm/llvm-project/issues/115133
204
204
# TODO: load/store, bitcast, getelementptr, phi
205
205
206
- exit = False
207
206
if args .type == 'all' or args .type == 'int' :
208
- data = []
209
- try :
207
+ def enumint ():
210
208
# Int Binops
211
209
for instr in ['add' , 'sub' , 'mul' , 'sdiv' , 'srem' , 'udiv' , 'urem' , 'and' , 'or' , 'xor' , 'shl' , 'ashr' , 'lshr' , 'smin' , 'smax' , 'umin' , 'umax' , 'uadd.sat' , 'usub.sat' , 'sadd.sat' , 'ssub.sat' , 'rotr' , 'rotl' ]:
212
210
for ty in inttypes ():
213
211
for (variant , extrasize ) in binop_variants (ty ):
214
- do (instr , variant , ty , ty , extrasize , data )
212
+ yield (instr , variant , ty , ty , extrasize , None )
215
213
216
214
# Int unops
217
215
for instr in ['abs' , 'bitreverse' , 'bswap' , 'ctlz' , 'cttz' , 'ctpop' ]:
218
216
for ty in inttypes ():
219
217
if instr == 'bswap' and ty .scalar == 'i8' :
220
218
continue
221
- do (instr , 'unop' , ty , ty , 0 , data )
219
+ yield (instr , 'unop' , ty , ty , 0 , None )
222
220
# TODO: not?
223
221
224
222
# Int triops
225
223
for instr in ['fshl' , 'fshr' ]:
226
224
for ty in inttypes ():
227
- do (instr , 'triop' , ty , ty , 0 , data )
225
+ yield (instr , 'triop' , ty , ty , 0 , None )
228
226
# TODO: select, icmp, fcmp, mla?
229
227
# TODO: fshl+const
230
228
@@ -239,29 +237,27 @@ def do(instr, variant, ty, ty2, extrasize, data, tyoverride=None):
239
237
240
238
# TODO: vecreduce.add, vecreduce.mul, vecreduce.and, vecreduce.or, vecreduce.xor, vecreduce.min/max's
241
239
242
- except KeyboardInterrupt :
243
- exit = True
240
+ pool = multiprocessing . Pool ( 16 )
241
+ data = pool . starmap ( do , enumint ())
244
242
with open (f"data-int{ '-' + args .mattr if args .mattr else '' } .json" , "w" ) as f :
245
243
json .dump (data , f , indent = 1 )
246
- if exit :
247
- sys .exit (1 )
244
+
248
245
249
246
if args .type == 'all' or args .type == 'fp' :
250
- data = []
251
- try :
247
+ def enumfp ():
252
248
# Floating point Binops
253
249
for instr in ['fadd' , 'fsub' , 'fmul' , 'fdiv' , 'frem' , 'minnum' , 'maxnum' , 'minimum' , 'maximum' , 'copysign' , 'pow' ]:
254
250
for ty in fptypes ():
255
251
for (variant , extrasize ) in binop_variants (ty ):
256
- do (instr , variant , ty , ty , extrasize , data )
252
+ yield (instr , variant , ty , ty , extrasize , None )
257
253
258
254
# FP unops
259
255
for instr in ['fneg' , 'fabs' , 'sqrt' , 'ceil' , 'floor' , 'trunc' , 'rint' , 'nearbyint' ]:
260
256
for ty in fptypes ():
261
- do (instr , 'unop' , ty , ty , 0 , data )
257
+ yield (instr , 'unop' , ty , ty , 0 , None )
262
258
for instr in ['fma' , 'fmuladd' ]:
263
259
for ty in fptypes ():
264
- do (instr , 'triop' , ty , ty , 0 , data )
260
+ yield (instr , 'triop' , ty , ty , 0 , None )
265
261
266
262
# TODO: fmul+fadd? select+fcmp
267
263
# TODO: fminimumnum, fmaximumnum
@@ -272,17 +268,14 @@ def do(instr, variant, ty, ty2, extrasize, data, tyoverride=None):
272
268
273
269
# TODO: vecreduce.fadd, vecreduce.fmul, vecreduce.fmin/max's
274
270
275
- except KeyboardInterrupt :
276
- exit = True
271
+ pool = multiprocessing . Pool ( 16 )
272
+ data = pool . starmap ( do , enumfp ())
277
273
with open (f"data-fp{ '-' + args .mattr if args .mattr else '' } .json" , "w" ) as f :
278
274
json .dump (data , f , indent = 1 )
279
- if exit :
280
- sys .exit (1 )
281
275
282
276
283
277
if args .type == 'all' or args .type == 'cast' :
284
- data = []
285
- try :
278
+ def enumcast ():
286
279
# TODO: zext, sext, trunc
287
280
# TODO: fpext, fptrunc, fptosisat, fptouisat
288
281
# TODO: lrint, llrint, lround, llround
@@ -293,42 +286,37 @@ def do(instr, variant, ty, ty2, extrasize, data, tyoverride=None):
293
286
for ty2 in inttypes ():
294
287
if ty1 .elts != ty2 .elts or ty1 .scalable != ty2 .scalable :
295
288
continue
296
- do (instr , 'cast ' + ty2 .scalar , ty1 , ty2 , 0 , data )
289
+ yield (instr , 'cast ' + ty2 .scalar , ty1 , ty2 , 0 , None )
297
290
for instr in ['sitofp' , 'uitofp' ]:
298
291
for ty1 in fptypes ():
299
292
for ty2 in inttypes ():
300
293
if ty1 .elts != ty2 .elts or ty1 .scalable != ty2 .scalable :
301
294
continue
302
- do (instr , 'cast ' + ty2 .scalar , ty2 , ty1 , 0 , data , str (ty1 ))
295
+ yield (instr , 'cast ' + ty2 .scalar , ty2 , ty1 , 0 , str (ty1 ))
303
296
304
- except KeyboardInterrupt :
305
- exit = True
297
+ pool = multiprocessing . Pool ( 16 )
298
+ data = pool . starmap ( do , enumcast ())
306
299
with open (f"data-cast{ '-' + args .mattr if args .mattr else '' } .json" , "w" ) as f :
307
300
json .dump (data , f , indent = 1 )
308
- if exit :
309
- sys .exit (1 )
310
301
311
302
312
303
if args .type == 'all' or args .type == 'vec' :
313
- data = []
314
- try :
304
+ def enumvec ():
315
305
for instr in ['insertelement' , 'extractelement' ]:
316
306
for ty in inttypes ():
317
307
if ty .elts == 1 :
318
308
continue
319
309
for variant in ['vecop0' , 'vecop1' , 'vecopvar' ]:
320
- do (instr , variant , ty , ty , 0 , data )
310
+ yield (instr , variant , ty , ty , 0 , None )
321
311
for ty in fptypes ():
322
312
if ty .elts == 1 :
323
313
continue
324
314
for variant in ['vecop0' , 'vecop1' , 'vecopvar' ]:
325
- do (instr , variant , ty , ty , 0 , data )
315
+ yield (instr , variant , ty , ty , 0 , None )
326
316
327
317
# TODO: shuffles
328
318
329
- except KeyboardInterrupt :
330
- exit = True
319
+ pool = multiprocessing . Pool ( 16 )
320
+ data = pool . starmap ( do , enumvec ())
331
321
with open (f"data-vec{ '-' + args .mattr if args .mattr else '' } .json" , "w" ) as f :
332
322
json .dump (data , f , indent = 1 )
333
- if exit :
334
- sys .exit (1 )
0 commit comments