HPCToolkit
lushpp.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 
3 # $Id$
4 
5 #import FindBin
6 #sys.path.insert(0, FindBin.Bin)
7 
8 import sys, traceback
9 import getopt
10 import string, re
11 #True = 1; False = 0
12 
13 DBG = False
14 
15 
16 
17 the_program = sys.argv[0];
18 the_usage = (
19 """Usage:
20  %s [options] < <cilk2c-file>
21  %s [options] <cilk2c-file>
22 
23 Given a cilk2c file, generate line directives to partition Cilk
24 overhead by overhead type.
25 
26 By necessity (given the use of line directives), assumes that function
27 calls are not nested in other statements.
28 
29 """) % (the_program, the_program)
30 
31 the_shortOpts = "o:vhd"
32 the_longOpts = ("output-file=",
33  "verbose", "help", "debug")
34 
35 
36 
37 class UsageExcept(Exception):
38  def __init__(self, msg):
39  self.msg = msg
40 
41  def __str__(self):
42  if (self.msg):
43  msg = ("%s: %s\n") % (the_program, self.msg)
44  msg = msg + ("Try `%s --help' for more information.\n"
45  % the_program)
46  else:
47  msg = the_usage
48  return msg
49 
50 class FatalError(Exception):
51  def __init__(self, msg):
52  self.msg = msg
53 
54  def __str__(self):
55  msg = ("%s: %s\n") % (the_program, self.msg)
56  return msg
57 
58 
59 
60 def main(argv=None):
61  if (argv is None):
62  argv = sys.argv
63 
64  the_globals = {
65  'inputFileNm' : None,
66  'verbose' : None,
67  'debug' : None
68  }
69 
70  try:
71  (opts, args) = parseCmdLine(argv, the_shortOpts, the_longOpts)
72  processCmdLine(the_globals, opts, args)
73  processFile(the_globals['inputFileNm']);
74  except (UsageExcept, FatalError), exc:
75  sys.stderr.write("%s" % exc)
76  return 1
77  except (SystemExit), exc:
78  return 0;
79  except:
80  sys.stderr.write("%s: Uncaught exception:\n" % the_program)
81  sys.stderr.write('-'*60+"\n")
82  traceback.print_exc(file=sys.stderr)
83  return 2
84  else:
85  return 0
86 
87 
88 def processCmdLine(ovars, opts, args):
89  """Given the results of parseCmdLine(), populate the 'ovars' dict
90  for this main routine."""
91  # Get optional arguments: verbose, help
92  if (opts.has_key('verbose') or opts.has_key('v')):
93  ovars['verbose'] = True
94  if (opts.has_key('debug') or opts.has_key('d')):
95  ovars['debug'] = True
96  if (opts.has_key('help') or opts.has_key('h')):
97  raise UsageExcept(None)
98 
99  if (len(args) == 0):
100  ovars['inputFileNm'] = None
101  elif (len(args) == 1):
102  ovars['inputFileNm'] = args[0]
103  else:
104  raise UsageExcept("Invalid number of arguments!")
105 
106 
107 
108 
109 def parseCmdLine(argv, shortOpts, longOpts):
110  """Given the inputs for getopt, return the parsed argv line as a
111  (dictionary-of-options, rest-of-arguments) tuple. Note that argv
112  should contain the full command line"""
113  try:
114  (opts, args) = getopt.getopt(argv[1:], shortOpts, longOpts)
115  except (getopt.error), msg:
116  raise UsageExcept(msg)
117  else:
118  dashRE = re.compile(r"^-{1,2}") # find leading dashes
119  dict = { }
120  for (o, a) in opts:
121  o = dashRE.sub('', o) # strip off leading dashes
122  dict[o] = a
123  return (dict, args)
124 
125 
126 def openInFile(filenm):
127  """Given a filename 'filenm', return an input stream. If 'filenm'
128  is NULL, return stdin; otherwise open the file."""
129  if (filenm):
130  try:
131  stream = open(filenm, "r")
132  except (IOError), msg:
133  raise FatalError(msg)
134  else:
135  stream = sys.stdin
136  return stream
137 
138 
139 def closeFile(filenm, stream):
140  if (filenm):
141  stream.close()
142 
143 
144 
145 CilkOverhead = {
146  'parallel' : [
147  'CILK2C_INIT_FRAME',
148  'CILK2C_PUSH_FRAME',
149 
150  'CILK2C_XPOP_FRAME_RESULT',
151  'CILK2C_XPOP_FRAME_NORESULT',
152 
153  'CILK2C_SET_NORESULT',
154  'CILK2C_BEFORE_RETURN_FAST',
155 
156  'CILK2C_START_THREAD_FAST',
157  'CILK2C_START_THREAD_SLOW',
158 
159  'CILK2C_BEFORE_RETURN_FAST', # part cp
160  'CILK2C_BEFORE_RETURN_SLOW', # part cp
161  'CILK2C_BEFORE_RETURN_INLET',
162 
163  'CILK2C_AT_SYNC_FAST', # part cp
164  'CILK2C_AT_THREAD_BOUNDARY_SLOW', # part cp
165 
166  # sync ---------------------
167  #'CILK2C_SYNC', # <-- FIXME should be a function
168 
169  'CILK2C_ABORT_SLOW',
170  'CILK2C_ABORT_STANDALONE',
171 
172  # cp -----------------------
173  'CILK2C_BEFORE_SPAWN_FAST',
174  'CILK2C_BEFORE_SPAWN_SLOW',
175  'CILK2C_AFTER_SPAWN_FAST',
176  'CILK2C_AFTER_SPAWN_SLOW',
177  'CILK2C_BEFORE_SYNC_SLOW',
178  'CILK2C_AFTER_SYNC_SLOW',
179  ],
180 
181  'sync' : [
182  ],
183 
184  'cp' : [
185  ],
186 
187  }
188 
189 class CilkMgr:
190  def __init__(self):
191  self.data = {
192  're_lst' : [ ],
193  }
194  self.makeREs(CilkOverhead['parallel'], 'parallel');
195  self.makeREs(CilkOverhead['sync'], 'sync');
196  self.makeREs(CilkOverhead['cp'], 'cp');
197 
198  # special RE for handling cilk import routines
199  redesc = REDesc()
200  redesc.make_cilk_import()
201  (self.data['re_lst']).append(redesc);
202 
203  def processLine(self, line, ppMgr):
204  new_line = line;
205 
206  for redesc in (self.data['re_lst']):
207  old_reObj = redesc.oldRE();
208  new_re = redesc.make_newRE(ppMgr.fileNm(), ppMgr.lineNo());
209 
210  new_line = old_reObj.sub(new_re, new_line)
211 
212  if (DBG and new_line != line): print "DBG:", new_line;
213  return new_line;
214 
215  # ------------------------------
216  def makeREs(self, overheadFnLst, overhead_ty):
217  for fn in overheadFnLst:
218  redesc = REDesc()
219  redesc.make_overhead(fn, overhead_ty)
220  (self.data['re_lst']).append(redesc);
221 
222 
223 class REDesc:
224  def __init__(self):
225  self.data = {
226  'old_reObj': None,
227  'new_re' : None,
228  'ty_ohead' : True,
229  }
230 
231  def oldRE(self):
232  return self.data['old_reObj']
233  def set_oldRE(self, x):
234  self.data['old_reObj'] = x
235 
236  def make_newRE(self, filenm, lineno):
237  if (self.isTyOverhead()):
238  txt = self.newRE() % (lineno, lineno, filenm);
239  else:
240  txt = self.newRE() % (lineno, filenm);
241  return txt;
242 
243  # ------------------------------
244 
245  def make_overhead(self, fn, overhead_ty):
246  cilk2c_pre = r'' #r';\s*'
247  cilk2c_post = r'[^;]*\s*;'
248  old_re = r"%s(%s%s)" % (cilk2c_pre, fn, cilk2c_post);
249  self.set_oldRE(re.compile(old_re));
250 
251  lush_mark = r'#line %s "lush:%s-overhead"' % ("%d", overhead_ty)
252  lush_unmark = r'#line %d "%s"'; # line cilk-fnm
253  self.set_newRE(r"\n%s\n \1\n%s\n " % (lush_mark, lush_unmark));
254 
255  def make_cilk_import(self):
256  old_re = r"(^.*_cilk\w+_import\(.+$)";
257  self.set_oldRE(re.compile(old_re));
258 
259  fix_mark = r'#line %d "%s"';
260  self.set_newRE(r"\1\n%s" % (fix_mark));
261  self.data['ty_ohead'] = False;
262 
263  # ------------------------------
264 
265  def newRE(self):
266  return self.data['new_re']
267  def set_newRE(self, x):
268  self.data['new_re'] = x
269 
270  def isTyOverhead(self):
271  return (self.data['ty_ohead']);
272 
273  def __str__(self):
274  return ("old: %s\nnew: %s") % (self.oldRE().pattern, self.newRE())
275 
276 
277 
278 
279 class CppMgr:
280  def __init__(self):
281  self.data = {
282  'dir_re' : re.compile(r"^#"),
283  'linedir_re' : re.compile(r'''^\#(?:line)?\s
284  \s*(\d+)
285  \s*(?:" ([^"]+) ")?''', re.X),
286  'mr_filenm' : None,
287  'mr_lnno' : 0, # as a number, not a string
288  }
289 
290  def isDirective(self, line):
291  return (self.data['dir_re']).match(line)
292 
293  def processDirLine(self, line):
294  m = (self.data['linedir_re']).match(line)
295  if (m):
296  self.set_lineNo(long(m.group(1)))
297  filenm = m.group(2)
298  if (filenm):
299  self.set_fileNm(filenm)
300  if (DBG): print "DBG:", self;
301 
302  def processNonDirLine(self):
303  if (self.data['mr_lnno']):
304  self.data['mr_lnno'] += 1;
305 
306  def fileNm(self):
307  return self.data['mr_filenm']
308  def set_fileNm(self, x):
309  self.data['mr_filenm'] = x
310 
311  def lineNo(self):
312  return self.data['mr_lnno']
313  def set_lineNo(self, x):
314  self.data['mr_lnno'] = x
315 
316  def __str__(self):
317  return ("%s:%s") % (self.fileNm(), self.lineNo())
318 
319 
320 def processFile(filenm):
321  """..."""
322  stream = openInFile(filenm)
323 
324  cilkMgr = CilkMgr()
325  cppMgr = CppMgr()
326 
327  for line in stream:
328  if (cppMgr.isDirective(line)):
329  cppMgr.processDirLine(line)
330  else:
331  line = cilkMgr.processLine(line, cppMgr)
332  cppMgr.processNonDirLine()
333 
334  print ("%s") % (line),
335 
336  closeFile(filenm, stream)
337 
338 
339 
340 
341 if (__name__ == "__main__"):
342  sys.exit(main())
343 
def set_lineNo(self, x)
Definition: lushpp.py:313
def set_oldRE(self, x)
Definition: lushpp.py:233
def parseCmdLine(argv, shortOpts, longOpts)
Definition: lushpp.py:109
def makeREs(self, overheadFnLst, overhead_ty)
Definition: lushpp.py:216
def __init__(self, msg)
Definition: lushpp.py:51
def make_cilk_import(self)
Definition: lushpp.py:255
def __str__(self)
Definition: lushpp.py:316
def openInFile(filenm)
Definition: lushpp.py:126
def set_fileNm(self, x)
Definition: lushpp.py:308
def isDirective(self, line)
Definition: lushpp.py:290
def main(argv=None)
Definition: lushpp.py:60
def newRE(self)
Definition: lushpp.py:265
def make_newRE(self, filenm, lineno)
Definition: lushpp.py:236
def processDirLine(self, line)
Definition: lushpp.py:293
def __init__(self)
Definition: lushpp.py:224
def make_overhead(self, fn, overhead_ty)
Definition: lushpp.py:245
def processNonDirLine(self)
Definition: lushpp.py:302
def __init__(self)
Definition: lushpp.py:190
def __str__(self)
Definition: lushpp.py:54
def fileNm(self)
Definition: lushpp.py:306
def __init__(self, msg)
Definition: lushpp.py:38
def isTyOverhead(self)
Definition: lushpp.py:270
def processFile(filenm)
Definition: lushpp.py:320
def closeFile(filenm, stream)
Definition: lushpp.py:139
def processCmdLine(ovars, opts, args)
Definition: lushpp.py:88
def processLine(self, line, ppMgr)
Definition: lushpp.py:203
def __str__(self)
Definition: lushpp.py:41
def __init__(self)
Definition: lushpp.py:280
def lineNo(self)
Definition: lushpp.py:311
def set_newRE(self, x)
Definition: lushpp.py:267
def oldRE(self)
Definition: lushpp.py:231
def __str__(self)
Definition: lushpp.py:273