1#
2# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6
7import subprocess
8import elf_file
9import elf_correlate
10import elf_parser
11import chronos.emitter
12import re
13from dot_utils import *
14import call_graph_utils
15import sys
16import traceback
17import graph_refine.problem as problem
18import imm_utils
19from graph_refine.target_objects import functions, functions_by_tag
20import graph_refine.target_objects as target_objects
21import cplex
22import conflict
23
24chronos_executable = "../../chronos4.2/est"
25
26fast_path = [
27'fastpath_restore',
28'fastpath_call',
29'fastpath_reply_wait',
30'slowpath'
31]
32
33dummy_funs = [
34'idle_thread', 'halt',
35] + fast_path
36
37#funs called by boot_funs only
38boot_funs_called = [
39'strncmp'
40]
41
42
43def makeGraph(f_name,fs):
44    p = fs[f_name].as_problem(problem.Problem)
45    toGraph(p,f_name)
46
47def runExtract(program_n_flags,cwd=None):
48    if cwd:
49        p = subprocess.Popen(program_n_flags,cwd=cwd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
50    else:
51        p = subprocess.Popen(program_n_flags,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
52    out,err = p.communicate()
53    retval = p.returncode
54    return retval, out, err
55
56#given the imm, call chronos and cplex to return (wcet,chronos_out,chornos_err)
57def getWcetFromImm(imm_file_name, generateILPOnly= False):
58    print 'running chronos...'
59    ret,out,err = runExtract([chronos_executable, imm_file_name])
60    print 'chronos completed, ret: %s, err: %s\n' % (ret,err)
61    if ret:
62        print 'Chronos FAILED\n out: %s\n err: %s\n' % (out,err)
63        print 'Chronos FAILED\n'
64        return None
65    else:
66        pass
67        print 'Chronos succeeded'
68    if generateILPOnly:
69        print "ILP file generated"
70        return None
71    return  float(cplex.cplexSolve(imm_file_name+'.ilp')),out,err
72
73
74def toElfImmFun(f,dir_name,load_counts):
75    ef = elfFile()
76    elf_fun = ef.funcs[elfFile().gFunName(f)]
77    imm_fun = elf_correlate.immFunc(elf_fun,load_counts=load_counts)
78    return elf_fun, imm_fun, ef
79
80def toImmFun(f,dir_name,load_counts=False):
81    _, imm_fun, _ = toElfImmFun(f,dir_name,load_counts)
82    return imm_fun
83
84def analyseFunction(f,asm_fs,dir_name,gen_heads,load_counts,emit_graphs, stopAtILP=False):
85    print '========analsying from entry point: %s===========' % f
86    elf_fun,imm_fun, ef = toElfImmFun(f, dir_name,load_counts)
87    #emit graphs with graph-refine
88    if emit_graphs:
89        makeGraph(f,asm_fs)
90
91    imm_fun.process()
92    if gen_heads:
93      print 'generating loop heads'
94      imm_utils.genLoopheads(imm_fun.bin_loops_by_fs,dir_name)
95      print 'loop heads generated'
96      if gen_heads:
97        return None
98      else:
99        import elf_correlate
100        #load the dummy loop counts
101        elf_correlate.immFunc().loaded_loops_by_fs = elf_correlate.loadCounts(dir_name)
102
103    #if emit_graphs:
104        #toDot(imm_fun)
105        #toDotBB(imm_fun)
106
107    emitter = chronos.emitter.ChronosEmitter(dir_name, f, imm_fun)
108    emitter.emitTopLevelFunction()
109
110    imm_file_name = emitter.imm_file_name
111
112    ret_g = getWcetFromImm(imm_file_name, stopAtILP)
113    if not ret_g:
114      return None
115    wcet, out_chronos_gg,err_chronos_gg = ret_g
116    if wcet:
117      print 'G2G-Chronos extracted, wcet: %s\n' % wcet
118      return wcet
119    return None
120
121def init(dir_name):
122    '''setup the target and initialise the elfFile'''
123    target_objects.load_target(dir_name)
124    sys.setrecursionlimit(2000)
125    import graph_refine.stack_logic as stack_logic
126    stack_logic.add_hooks ()
127    #silence graph-refine outputs that  we don't care about when doing wcet
128    def silent_tracer (s,v):
129        if s.startswith('Loop') or re.search(r'\s*\(=',s) or re.search(r'\s*\(',s):
130          return
131        if s.startswith('requests') or s.startswith('Result:') or s.startswith('Now'):
132          return
133        if s.startswith('testing') or s.startswith('done') or s.startswith('rep_graph'):
134          return
135        if s.startswith('Testing') or s.startswith('Group'):
136          return
137        print s
138
139    target_objects.tracer[0] = silent_tracer
140    elf_parser.parseElf(dir_name)
141    asm_fs = elfFile().asm_fs
142    tran_call_graph = call_graph_utils.transitiveCallGraph(asm_fs,dir_name,dummy_funs)
143
144    elfFile().tcg = tran_call_graph
145    elfFile().asm_idents = None
146    elfFile().immed = None
147    return asm_fs
148
149def bench(dir_name, entry_point_function, gen_heads,load_counts, interactive, parse_only=False, conflict_file=None):
150    asm_fs = init(dir_name)
151    functions = target_objects.functions
152    if parse_only or interactive:
153        t = entry_point_function
154        i = toImmFun(t,dir_name,load_counts=load_counts)
155        i.process()
156        return
157    dn = dir_name
158    emit_graphs = False
159    wcet = analyseFunction(entry_point_function,asm_fs, dir_name, gen_heads, load_counts, emit_graphs=emit_graphs)
160    return wcet
161
162