]> rtime.felk.cvut.cz Git - linux-conf-perf.git/blob - scripts/configurations.py
Fix generate single configuration
[linux-conf-perf.git] / scripts / configurations.py
1 import os
2 import sys
3 import tempfile
4 import shutil
5 import subprocess
6 import time
7 import hashlib
8
9 import utils
10 from conf import conf
11 from conf import sf
12 import exceptions
13 import database
14
15 def __buildtempcnf__(variable_count, files, strlines):
16         """ Builds temporally file for cnf formulas
17           variable_count - number of variables in formulas
18           files          - list of files with formulas
19           strlines       - list of string lines with formulas"""
20         lines = set()
21         # Copy strlines
22         for ln in strlines:
23                 lines.add(ln)
24         # Files
25         for file in files:
26                 with open(file, 'r') as f:
27                         for ln in f:
28                                 lines.add(ln.rstrip())
29
30         first_line = "p cnf " + str(variable_count) + " " + str(len(lines))
31
32         wfile = tempfile.NamedTemporaryFile(delete=False)
33         wfile.write(bytes(first_line + '\n', 'UTF-8'))
34         for ln in lines:
35                 wfile.write(bytes(ln + ' 0\n', 'UTF-8'))
36         wfile.close()
37         return wfile.name
38
39 def __exec_sat__(file, args):
40         """Executes SAT solver and returns configuration."""
41         picosat_cmd = [sf(conf.picosat), file]
42         picosat_cmd += conf.picosat_args
43         stdout = utils.callsubprocess('picosat', picosat_cmd, conf.picosat_output,
44                         True, allow_all_exit_codes = True)
45
46         rtn = []
47         solut = []
48         for line in stdout:
49                 if line[0] == 's':
50                         try:
51                                 solut.remove(0)
52                                 rtn.append(solut)
53                         except ValueError:
54                                 pass
55                         solut = []
56                         if not line.rstrip() == 's SATISFIABLE':
57                                 raise exceptions.NoSolution()
58                 elif line[0] == 'v':
59                         for sl in line[2:].split():
60                                 solut.append(int(sl))
61         try:
62                 solut.remove(0)
63                 rtn.append(solut)
64         except ValueError:
65                 pass
66         return rtn
67
68 def __write_temp_config_file__(con, conf_num):
69         # Ensure smap existence
70         utils.build_symbol_map()
71         # Write temporally file
72         wfile = tempfile.NamedTemporaryFile(delete=False)
73         for s in con:
74                 if s < 0:
75                         nt = True
76                         s *= -1
77                 else:
78                         nt = False
79                 if s > int(conf_num):
80                         break;
81                 if 'NONAMEGEN' in utils.smap[s]: # ignore generated names
82                         continue
83                 wfile.write(bytes('CONFIG_' + utils.smap[s] + '=',
84                         sys.getdefaultencoding()))
85                 if not nt:
86                         wfile.write(bytes('y', sys.getdefaultencoding()))
87                 else:
88                         wfile.write(bytes('n', sys.getdefaultencoding()))
89                 wfile.write(bytes('\n', sys.getdefaultencoding()))
90         wfile.close()
91         return wfile.name
92
93 def __load_config_file__(file):
94         rtn = dict()
95         with open(file, 'r') as f:
96                 for ln in f:
97                         if ln[0] == '#' or not '=' in ln:
98                                 continue
99                         indx = ln.index('=')
100                         if (ln[indx + 1] == 'y'):
101                                 rtn[ln[7:indx]] = True
102                         else:
103                                 rtn[ln[7:indx]] = False
104         return rtn
105
106 def __calchash__(file):
107         """Calculates hash from configuration file"""
108         # Build hashconfigsort
109         csort = []
110         try:
111                 with open(conf.hashconfigsort, 'r') as f:
112                         for ln in f:
113                                 csort.append(ln.rstrip())
114         except FileNotFoundError:
115                 pass
116
117         con = __load_config_file__(file)
118         cstr = ""
119         for c in csort:
120                 try:
121                         if con[c]:
122                                 cstr += c
123                 except ValueError:
124                         pass
125
126         # Add missing
127         csortfile = open(sf(conf.hashconfigsort), 'a');
128         for key, val in con.items():
129                 try:
130                         csort.index(key)
131                 except ValueError:
132                         indx = len(csort)
133                         csort.append(key)
134                         csortfile.write(key + '\n')
135                         if val:
136                                 cstr += key
137         csortfile.close()
138
139         hsh = hashlib.md5(bytes(cstr, 'UTF-8'))
140         return hsh.hexdigest()
141
142 def __register_conf__(con, conf_num, generator):
143         dtb = database.database()
144         # Solution to configuration
145         wfile = __write_temp_config_file__(con, conf_num)
146         hsh = __calchash__(wfile)
147         filen = os.path.join(sf(conf.configurations_folder), hsh)
148         hshf = hsh
149         if os.path.isfile(filen):
150                 if compare(filen, wfile):
151                         print("I: Generated existing configuration.")
152                         return False
153                 else:
154                         print("W: Generated configuration with collision hash.")
155                         # TODO this might have to be tweaked
156                         raise Exception()
157         shutil.move(wfile, filen)
158         dtb.add_configuration(hsh, hshf, generator)
159         return True
160
161 def __generate_single__(var_num, conf_num):
162         measure_list = set()
163         if not os.path.isfile(sf(conf.single_generated_file)):
164                 with open(sf(conf.measure_file), 'r') as fi:
165                         for ln in fi:
166                                 measure_list.add(int(ln))
167         else:
168                 with open(sf(conf.single_generated_file), 'r') as f:
169                         for ln in f:
170                                 measure_list.add(int(ln))
171         if not measure_list:
172                 return False
173         tfile = __buildtempcnf__(var_num, (sf(conf.rules_file),
174                 sf(conf.fixed_file)), (str(measure_list.pop())))
175         with open(sf(conf.single_generated_file), 'w') as fo:
176                 fo.writelines(measure_list)
177         try:
178                 confs = __exec_sat__(tfile, ['-i', '0'])
179                 for con in confs:
180                         __register_conf__(con, conf_num, 'single-sat')
181         except exceptions.NoSolution:
182                 os.remove(tfile)
183                 return __generate_single__(var_num, conf_num)
184         finally:
185                 os.remove(tfile)
186         return True
187
188 def __generate_random__(var_num, conf_num):
189         tfile = __buildtempcnf__(var_num, (sf(conf.rules_file), sf(conf.fixed_file)), ())
190         try:
191                 confs = __exec_sat__(tfile, ['-i', '3'])
192                 for con in confs:
193                         if not __register_conf__(con, conf_num, 'random-sat'):
194                                 __generate_random__(var_num, conf_num)
195         finally:
196                 os.remove(tfile)
197         return True
198
199 def generate():
200         """Collect boolean equations from files rules and required
201         And get solution with picosat
202         """
203         # Check if rules_file exist. If it was generated.
204         if not os.path.isfile(sf(conf.rules_file)):
205                 raise exceptions.MissingFile(conf.rules_file,"Run parse_kconfig.")
206         if not os.path.isfile(sf(conf.fixed_file)):
207                 raise exceptions.MissingFile(conf.required_file,"Run allconfig and initialization process.")
208
209         # Load variable count
210         with open(sf(conf.variable_count_file)) as f:
211                 var_num = f.readline().rstrip()
212                 conf_num = f.readline().rstrip()
213
214         if __generate_single__(var_num, conf_num):
215                 return
216         elif __generate_random__(var_num, conf_num):
217                 return
218
219         raise exceptions.NoNewConfiguration()
220
221 def compare(file1, file2):
222         """Compared two configuration"""
223         conf1 = __load_config_file__(file1)
224         conf2 = __load_config_file__(file2)
225
226         # This is not exactly best comparison method
227         for key, val in conf1.items():
228                 try:
229                         if conf2[key] != val:
230                                 return False
231                 except ValueError:
232                         return False
233         for key, val in conf2.items():
234                 try:
235                         if conf1[key] != val:
236                                 return False
237                 except ValueError:
238                         return False
239         return True