xref: /petsc/config/query_tests.py (revision 4e028deda04a5d73df26761e1bcab63d0550a952)
16f5e9bd5SScott Kruger#!/usr/bin/env python
26f5e9bd5SScott Krugerimport fnmatch
36f5e9bd5SScott Krugerimport glob
46f5e9bd5SScott Krugerimport inspect
56f5e9bd5SScott Krugerimport os
66f5e9bd5SScott Krugerimport optparse
76f5e9bd5SScott Krugerimport pickle
86f5e9bd5SScott Krugerimport re
96f5e9bd5SScott Krugerimport sys
106f5e9bd5SScott Kruger
116f5e9bd5SScott Krugerthisfile = os.path.abspath(inspect.getfile(inspect.currentframe()))
126f5e9bd5SScott Krugerpdir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(thisfile)))))
136f5e9bd5SScott Krugersys.path.insert(0, os.path.join(pdir, 'config'))
146f5e9bd5SScott Kruger
156f5e9bd5SScott Krugerimport testparse
166f5e9bd5SScott Krugerfrom gmakegentest import nameSpace
176f5e9bd5SScott Kruger
186f5e9bd5SScott Kruger
196f5e9bd5SScott Kruger"""
206f5e9bd5SScott Kruger  Tool for querying the tests.
216f5e9bd5SScott Kruger
226f5e9bd5SScott Kruger  Which tests to query?  Two options:
236f5e9bd5SScott Kruger      1. Query only the tests that are run for a given configuration.
246f5e9bd5SScott Kruger      2. Query all of the test files in the source directory
256f5e9bd5SScott Kruger  For #1:
266f5e9bd5SScott Kruger     Use dataDict as written out by gmakegentest.py in $PETSC_ARCH/$TESTBASE
276f5e9bd5SScott Kruger  For #2:
286f5e9bd5SScott Kruger     Walk the entire tree parsing the files as we go along using testparse.
296f5e9bd5SScott Kruger     The tree walker is simpler than what is in gmakegentest.py
306f5e9bd5SScott Kruger
316f5e9bd5SScott Kruger  The dataDict follows that generated by testparse.  gmakegentest.py does
326f5e9bd5SScott Kruger  further manipulations of the dataDict to handle things like for loops
336f5e9bd5SScott Kruger  so if using #2, those modifications are not included.
346f5e9bd5SScott Kruger
356f5e9bd5SScott Kruger  Querying:
366f5e9bd5SScott Kruger      The dataDict dictionary is then "inverted" to create a dictionary with the
376f5e9bd5SScott Kruger      range of field values as keys and list test names as the values.  This
386f5e9bd5SScott Kruger      allows fast searching
396f5e9bd5SScott Kruger
406f5e9bd5SScott Kruger"""
416f5e9bd5SScott Kruger
426f5e9bd5SScott Krugerdef query(invDict,label):
436f5e9bd5SScott Kruger    """
446f5e9bd5SScott Kruger    Search the keys using fnmatch to find matching names and return list with
456f5e9bd5SScott Kruger    the results
466f5e9bd5SScott Kruger    """
476f5e9bd5SScott Kruger    results=[]
485b6dee57SScott Kruger    if 'name' in invDict:
495b6dee57SScott Kruger        return fnmatch.filter(invDict['name'],label)
505b6dee57SScott Kruger
516f5e9bd5SScott Kruger    for key in invDict:
526f5e9bd5SScott Kruger        if fnmatch.filter([key],label):
536f5e9bd5SScott Kruger            # Do not return values with not unless label itself has not
546f5e9bd5SScott Kruger            if label.startswith('!') and not key.startswith('!'): continue
556f5e9bd5SScott Kruger            if not label.startswith('!') and key.startswith('!'): continue
566f5e9bd5SScott Kruger            results += invDict[key]
576f5e9bd5SScott Kruger
586f5e9bd5SScott Kruger    return results
596f5e9bd5SScott Kruger
606f5e9bd5SScott Krugerdef get_inverse_dictionary(dataDict,field,srcdir):
616f5e9bd5SScott Kruger    """
626f5e9bd5SScott Kruger    Create a dictionary with the values of field as the keys, and the name of
636f5e9bd5SScott Kruger    the tests as the results.
646f5e9bd5SScott Kruger    """
656f5e9bd5SScott Kruger    invDict={}
665b6dee57SScott Kruger    if field == 'name': invDict['name']=[]
676f5e9bd5SScott Kruger    for root in dataDict:
686f5e9bd5SScott Kruger      for exfile in dataDict[root]:
696f5e9bd5SScott Kruger        for test in dataDict[root][exfile]:
70aec279ffSScott Kruger          if test in testparse.buildkeys: continue
716f5e9bd5SScott Kruger          defroot = testparse.getDefaultOutputFileRoot(test)
726f5e9bd5SScott Kruger          name=nameSpace(defroot,os.path.relpath(root,srcdir))
735b6dee57SScott Kruger          if field == 'name':
745b6dee57SScott Kruger              invDict['name'].append(name)
755b6dee57SScott Kruger              continue
765b6dee57SScott Kruger          if field not in dataDict[root][exfile][test]: continue
776f5e9bd5SScott Kruger          values=dataDict[root][exfile][test][field]
786f5e9bd5SScott Kruger
796f5e9bd5SScott Kruger          for val in values.split():
806f5e9bd5SScott Kruger              if val in invDict:
816f5e9bd5SScott Kruger                  invDict[val].append(name)
826f5e9bd5SScott Kruger              else:
836f5e9bd5SScott Kruger                  invDict[val] = [name]
846f5e9bd5SScott Kruger    return invDict
856f5e9bd5SScott Kruger
86*4e028dedSScott Krugerdef get_gmakegentest_data(testdir,petsc_dir,petsc_arch):
876f5e9bd5SScott Kruger    """
886f5e9bd5SScott Kruger     Write out the dataDict into a pickle file
896f5e9bd5SScott Kruger    """
906f5e9bd5SScott Kruger    # This needs to be consistent with gmakegentest.py of course
91*4e028dedSScott Kruger    pkl_file=os.path.join(testdir,'datatest.pkl')
92*4e028dedSScott Kruger    # If it doesn't exist, then we need to regenerate
93*4e028dedSScott Kruger    if not os.path.exists(pkl_file):
94*4e028dedSScott Kruger      startdir=os.path.abspath(os.curdir)
95*4e028dedSScott Kruger      os.chdir(petsc_dir)
96*4e028dedSScott Kruger      args='--petsc-dir='+petsc_dir+' --petsc-arch='+petsc_arch+' --testdir='+testdir
97*4e028dedSScott Kruger      buf = os.popen('config/gmakegentest.py '+args).read()
98*4e028dedSScott Kruger      os.chdir(startdir)
99*4e028dedSScott Kruger
100*4e028dedSScott Kruger    fd = open(pkl_file, 'rb')
1016f5e9bd5SScott Kruger    dataDict=pickle.load(fd)
1026f5e9bd5SScott Kruger    fd.close()
1036f5e9bd5SScott Kruger    return dataDict
1046f5e9bd5SScott Kruger
1056f5e9bd5SScott Krugerdef walktree(top):
1066f5e9bd5SScott Kruger    """
1076f5e9bd5SScott Kruger    Walk a directory tree, starting from 'top'
1086f5e9bd5SScott Kruger    """
1096f5e9bd5SScott Kruger    verbose = False
1106f5e9bd5SScott Kruger    dataDict = {}
1116f5e9bd5SScott Kruger    alldatafiles = []
1126f5e9bd5SScott Kruger    for root, dirs, files in os.walk(top, topdown=False):
1136f5e9bd5SScott Kruger        if "examples" not in root: continue
1146f5e9bd5SScott Kruger        if root == 'output': continue
1156f5e9bd5SScott Kruger        if '.dSYM' in root: continue
1166f5e9bd5SScott Kruger        if verbose: print(root)
1176f5e9bd5SScott Kruger
1186f5e9bd5SScott Kruger        dataDict[root] = {}
1196f5e9bd5SScott Kruger
1206f5e9bd5SScott Kruger        for exfile in files:
1216f5e9bd5SScott Kruger            # Ignore emacs files
1226f5e9bd5SScott Kruger            if exfile.startswith("#") or exfile.startswith(".#"): continue
1236f5e9bd5SScott Kruger            ext=os.path.splitext(exfile)[1]
1246f5e9bd5SScott Kruger            if ext[1:] not in ['c','cxx','cpp','cu','F90','F']: continue
1256f5e9bd5SScott Kruger
1266f5e9bd5SScott Kruger            # Convenience
1276f5e9bd5SScott Kruger            fullex = os.path.join(root, exfile)
1286f5e9bd5SScott Kruger            if verbose: print('   --> '+fullex)
1296f5e9bd5SScott Kruger            dataDict[root].update(testparse.parseTestFile(fullex, 0))
1306f5e9bd5SScott Kruger
1316f5e9bd5SScott Kruger    return dataDict
1326f5e9bd5SScott Kruger
133*4e028dedSScott Krugerdef do_query(use_source, startdir, srcdir, testdir, petsc_dir, petsc_arch, field, label):
1346f5e9bd5SScott Kruger    """
1356f5e9bd5SScott Kruger    Do the actual query
1366f5e9bd5SScott Kruger    This part of the code is placed here instead of main()
1376f5e9bd5SScott Kruger    to show how one could translate this into ipython/jupyer notebook
1386f5e9bd5SScott Kruger    commands for more advanced queries
1396f5e9bd5SScott Kruger    """
1406f5e9bd5SScott Kruger    # Get dictionary
1416f5e9bd5SScott Kruger    if use_source:
1426f5e9bd5SScott Kruger        dataDict=walktree(startdir)
1436f5e9bd5SScott Kruger    else:
144*4e028dedSScott Kruger        dataDict=get_gmakegentest_data(testdir, petsc_dir, petsc_arch)
1456f5e9bd5SScott Kruger
1466f5e9bd5SScott Kruger    # Get inverse dictionary for searching
1476f5e9bd5SScott Kruger    invDict=get_inverse_dictionary(dataDict, field, srcdir)
1485b6dee57SScott Kruger    #print(invDict)
1496f5e9bd5SScott Kruger
1506f5e9bd5SScott Kruger    # Now do query
1516f5e9bd5SScott Kruger    resList=query(invDict, label)
1526f5e9bd5SScott Kruger
1536f5e9bd5SScott Kruger    # Print in flat list suitable for use by gmakefile.test
1546f5e9bd5SScott Kruger    print(' '.join(resList))
1556f5e9bd5SScott Kruger
1566f5e9bd5SScott Kruger    return
1576f5e9bd5SScott Kruger
1586f5e9bd5SScott Krugerdef main():
1596f5e9bd5SScott Kruger    parser = optparse.OptionParser(usage="%prog [options] field match_pattern")
1606f5e9bd5SScott Kruger    parser.add_option('-s', '--startdir', dest='startdir',
1616f5e9bd5SScott Kruger                      help='Where to start the recursion if not srcdir',
1626f5e9bd5SScott Kruger                      default='')
163aec279ffSScott Kruger    parser.add_option('-p', '--petsc-dir', dest='petsc_dir',
164aec279ffSScott Kruger                      help='Set PETSC_DIR different from environment',
1656f5e9bd5SScott Kruger                      default=os.environ.get('PETSC_DIR'))
1666f5e9bd5SScott Kruger    parser.add_option('-a', '--petsc-arch', dest='petsc_arch',
1676f5e9bd5SScott Kruger                      help='Set PETSC_ARCH different from environment',
1686f5e9bd5SScott Kruger                      default=os.environ.get('PETSC_ARCH'))
1696f5e9bd5SScott Kruger    parser.add_option('--srcdir', dest='srcdir',
1706f5e9bd5SScott Kruger                      help='Set location of sources different from PETSC_DIR/src.  Must be full path.',
1716f5e9bd5SScott Kruger                      default='src')
1726f5e9bd5SScott Kruger    parser.add_option('-t', '--testdir', dest='testdir',
1736f5e9bd5SScott Kruger                      help='Test directory if not PETSC_ARCH/tests.  Must be full path',
1746f5e9bd5SScott Kruger                      default='tests')
1756f5e9bd5SScott Kruger    parser.add_option('-u', '--use-source', action="store_false",
1766f5e9bd5SScott Kruger                      dest='use_source',
1776f5e9bd5SScott Kruger                      help='Query all sources rather than those configured in PETSC_ARCH')
1786f5e9bd5SScott Kruger
1796f5e9bd5SScott Kruger    opts, args = parser.parse_args()
1806f5e9bd5SScott Kruger
1816f5e9bd5SScott Kruger    # Argument Sanity checks
1826f5e9bd5SScott Kruger    if len(args) != 2:
1836f5e9bd5SScott Kruger        parser.print_usage()
1846f5e9bd5SScott Kruger        print('Arguments: ')
1856f5e9bd5SScott Kruger        print('  field:          Field to search for; e.g., requires')
1865b6dee57SScott Kruger        print('                  To just match names, use "name"')
1876f5e9bd5SScott Kruger        print('  match_pattern:  Matching pattern for field; e.g., cuda')
1886f5e9bd5SScott Kruger        return
1896f5e9bd5SScott Kruger
1906f5e9bd5SScott Kruger    # Process arguments and options -- mostly just paths here
1916f5e9bd5SScott Kruger    field=args[0]
1926f5e9bd5SScott Kruger    match=args[1]
1936f5e9bd5SScott Kruger
1946f5e9bd5SScott Kruger    petsc_dir = opts.petsc_dir
1956f5e9bd5SScott Kruger    petsc_arch = opts.petsc_arch
1966f5e9bd5SScott Kruger    petsc_full_arch = os.path.join(petsc_dir, petsc_arch)
1976f5e9bd5SScott Kruger
1986f5e9bd5SScott Kruger    if opts.srcdir == 'src':
1996f5e9bd5SScott Kruger      petsc_full_src = os.path.join(petsc_dir, 'src')
2006f5e9bd5SScott Kruger    else:
2016f5e9bd5SScott Kruger      petsc_full_src = opts.srcdir
2026f5e9bd5SScott Kruger    if opts.testdir == 'tests':
2036f5e9bd5SScott Kruger      petsc_full_test = os.path.join(petsc_full_arch, 'tests')
2046f5e9bd5SScott Kruger    else:
2056f5e9bd5SScott Kruger      petsc_full_test = opts.testdir
2066f5e9bd5SScott Kruger    if opts.startdir:
2076f5e9bd5SScott Kruger      startdir=opts.startdir=petsc_full_src
2086f5e9bd5SScott Kruger    else:
2096f5e9bd5SScott Kruger      startdir=petsc_full_src
2106f5e9bd5SScott Kruger
2116f5e9bd5SScott Kruger    # Options Sanity checks
2126f5e9bd5SScott Kruger    if not os.path.isdir(petsc_dir):
2136f5e9bd5SScott Kruger        print("PETSC_DIR must be a directory")
2146f5e9bd5SScott Kruger        return
2156f5e9bd5SScott Kruger
2166f5e9bd5SScott Kruger    if not opts.use_source:
2176f5e9bd5SScott Kruger        if not os.path.isdir(petsc_full_arch):
2186f5e9bd5SScott Kruger            print("PETSC_DIR/PETSC_ARCH must be a directory")
2196f5e9bd5SScott Kruger            return
2206f5e9bd5SScott Kruger        elif not os.path.isdir(petsc_full_test):
2216f5e9bd5SScott Kruger            print("Testdir must be a directory"+petsc_full_test)
2226f5e9bd5SScott Kruger            return
2236f5e9bd5SScott Kruger    else:
2246f5e9bd5SScott Kruger        if not os.path.isdir(petsc_full_src):
2256f5e9bd5SScott Kruger            print("Source directory must be a directory"+petsc_full_src)
2266f5e9bd5SScott Kruger            return
2276f5e9bd5SScott Kruger
2286f5e9bd5SScott Kruger    # Do the actual query
229*4e028dedSScott Kruger    do_query(opts.use_source, startdir, petsc_full_src, petsc_full_test,
230*4e028dedSScott Kruger             petsc_dir, petsc_arch, field, match)
2316f5e9bd5SScott Kruger
2326f5e9bd5SScott Kruger    return
2336f5e9bd5SScott Kruger
2346f5e9bd5SScott Kruger
2356f5e9bd5SScott Krugerif __name__ == "__main__":
2366f5e9bd5SScott Kruger        main()
237