xref: /petsc/config/query_tests.py (revision 5b6dee571a933a5092f178962ae368faa10054e5)
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=[]
48*5b6dee57SScott Kruger    if 'name' in invDict:
49*5b6dee57SScott Kruger        return fnmatch.filter(invDict['name'],label)
50*5b6dee57SScott 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={}
66*5b6dee57SScott 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]:
706f5e9bd5SScott Kruger          defroot = testparse.getDefaultOutputFileRoot(test)
716f5e9bd5SScott Kruger          name=nameSpace(defroot,os.path.relpath(root,srcdir))
72*5b6dee57SScott Kruger          if field == 'name':
73*5b6dee57SScott Kruger              if 'SKIP' in name: continue
74*5b6dee57SScott Kruger              invDict['name'].append(name)
75*5b6dee57SScott Kruger              continue
76*5b6dee57SScott 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
866f5e9bd5SScott Krugerdef get_gmakegentest_data(testdir):
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
916f5e9bd5SScott Kruger    fd = open(os.path.join(testdir,'datatest.pkl'), 'rb')
926f5e9bd5SScott Kruger    dataDict=pickle.load(fd)
936f5e9bd5SScott Kruger    fd.close()
946f5e9bd5SScott Kruger    return dataDict
956f5e9bd5SScott Kruger
966f5e9bd5SScott Krugerdef walktree(top):
976f5e9bd5SScott Kruger    """
986f5e9bd5SScott Kruger    Walk a directory tree, starting from 'top'
996f5e9bd5SScott Kruger    """
1006f5e9bd5SScott Kruger    verbose = False
1016f5e9bd5SScott Kruger    dataDict = {}
1026f5e9bd5SScott Kruger    alldatafiles = []
1036f5e9bd5SScott Kruger    for root, dirs, files in os.walk(top, topdown=False):
1046f5e9bd5SScott Kruger        if "examples" not in root: continue
1056f5e9bd5SScott Kruger        if root == 'output': continue
1066f5e9bd5SScott Kruger        if '.dSYM' in root: continue
1076f5e9bd5SScott Kruger        if verbose: print(root)
1086f5e9bd5SScott Kruger
1096f5e9bd5SScott Kruger        dataDict[root] = {}
1106f5e9bd5SScott Kruger
1116f5e9bd5SScott Kruger        for exfile in files:
1126f5e9bd5SScott Kruger            # Ignore emacs files
1136f5e9bd5SScott Kruger            if exfile.startswith("#") or exfile.startswith(".#"): continue
1146f5e9bd5SScott Kruger            ext=os.path.splitext(exfile)[1]
1156f5e9bd5SScott Kruger            if ext[1:] not in ['c','cxx','cpp','cu','F90','F']: continue
1166f5e9bd5SScott Kruger
1176f5e9bd5SScott Kruger            # Convenience
1186f5e9bd5SScott Kruger            fullex = os.path.join(root, exfile)
1196f5e9bd5SScott Kruger            if verbose: print('   --> '+fullex)
1206f5e9bd5SScott Kruger            dataDict[root].update(testparse.parseTestFile(fullex, 0))
1216f5e9bd5SScott Kruger
1226f5e9bd5SScott Kruger    return dataDict
1236f5e9bd5SScott Kruger
1246f5e9bd5SScott Krugerdef do_query(use_source, startdir, srcdir, testdir, field, label):
1256f5e9bd5SScott Kruger    """
1266f5e9bd5SScott Kruger    Do the actual query
1276f5e9bd5SScott Kruger    This part of the code is placed here instead of main()
1286f5e9bd5SScott Kruger    to show how one could translate this into ipython/jupyer notebook
1296f5e9bd5SScott Kruger    commands for more advanced queries
1306f5e9bd5SScott Kruger    """
1316f5e9bd5SScott Kruger    # Get dictionary
1326f5e9bd5SScott Kruger    if use_source:
1336f5e9bd5SScott Kruger        dataDict=walktree(startdir)
1346f5e9bd5SScott Kruger    else:
1356f5e9bd5SScott Kruger        dataDict=get_gmakegentest_data(testdir)
1366f5e9bd5SScott Kruger
1376f5e9bd5SScott Kruger    # Get inverse dictionary for searching
1386f5e9bd5SScott Kruger    invDict=get_inverse_dictionary(dataDict, field, srcdir)
139*5b6dee57SScott Kruger    #print(invDict)
1406f5e9bd5SScott Kruger
1416f5e9bd5SScott Kruger    # Now do query
1426f5e9bd5SScott Kruger    resList=query(invDict, label)
1436f5e9bd5SScott Kruger
1446f5e9bd5SScott Kruger    # Print in flat list suitable for use by gmakefile.test
1456f5e9bd5SScott Kruger    print(' '.join(resList))
1466f5e9bd5SScott Kruger
1476f5e9bd5SScott Kruger    return
1486f5e9bd5SScott Kruger
1496f5e9bd5SScott Krugerdef main():
1506f5e9bd5SScott Kruger    parser = optparse.OptionParser(usage="%prog [options] field match_pattern")
1516f5e9bd5SScott Kruger    parser.add_option('-s', '--startdir', dest='startdir',
1526f5e9bd5SScott Kruger                      help='Where to start the recursion if not srcdir',
1536f5e9bd5SScott Kruger                      default='')
1546f5e9bd5SScott Kruger    parser.add_option('-p', '--petsc_dir', dest='petsc_dir',
1556f5e9bd5SScott Kruger                      help='Set PETSC_ARCH different from environment',
1566f5e9bd5SScott Kruger                      default=os.environ.get('PETSC_DIR'))
1576f5e9bd5SScott Kruger    parser.add_option('-a', '--petsc-arch', dest='petsc_arch',
1586f5e9bd5SScott Kruger                      help='Set PETSC_ARCH different from environment',
1596f5e9bd5SScott Kruger                      default=os.environ.get('PETSC_ARCH'))
1606f5e9bd5SScott Kruger    parser.add_option('--srcdir', dest='srcdir',
1616f5e9bd5SScott Kruger                      help='Set location of sources different from PETSC_DIR/src.  Must be full path.',
1626f5e9bd5SScott Kruger                      default='src')
1636f5e9bd5SScott Kruger    parser.add_option('-t', '--testdir', dest='testdir',
1646f5e9bd5SScott Kruger                      help='Test directory if not PETSC_ARCH/tests.  Must be full path',
1656f5e9bd5SScott Kruger                      default='tests')
1666f5e9bd5SScott Kruger    parser.add_option('-u', '--use-source', action="store_false",
1676f5e9bd5SScott Kruger                      dest='use_source',
1686f5e9bd5SScott Kruger                      help='Query all sources rather than those configured in PETSC_ARCH')
1696f5e9bd5SScott Kruger
1706f5e9bd5SScott Kruger    opts, args = parser.parse_args()
1716f5e9bd5SScott Kruger
1726f5e9bd5SScott Kruger    # Argument Sanity checks
1736f5e9bd5SScott Kruger    if len(args) != 2:
1746f5e9bd5SScott Kruger        parser.print_usage()
1756f5e9bd5SScott Kruger        print('Arguments: ')
1766f5e9bd5SScott Kruger        print('  field:          Field to search for; e.g., requires')
177*5b6dee57SScott Kruger        print('                  To just match names, use "name"')
1786f5e9bd5SScott Kruger        print('  match_pattern:  Matching pattern for field; e.g., cuda')
1796f5e9bd5SScott Kruger        return
1806f5e9bd5SScott Kruger
1816f5e9bd5SScott Kruger    # Process arguments and options -- mostly just paths here
1826f5e9bd5SScott Kruger    field=args[0]
1836f5e9bd5SScott Kruger    match=args[1]
1846f5e9bd5SScott Kruger
1856f5e9bd5SScott Kruger    petsc_dir = opts.petsc_dir
1866f5e9bd5SScott Kruger    petsc_arch = opts.petsc_arch
1876f5e9bd5SScott Kruger    petsc_full_arch = os.path.join(petsc_dir, petsc_arch)
1886f5e9bd5SScott Kruger
1896f5e9bd5SScott Kruger    if opts.srcdir == 'src':
1906f5e9bd5SScott Kruger      petsc_full_src = os.path.join(petsc_dir, 'src')
1916f5e9bd5SScott Kruger    else:
1926f5e9bd5SScott Kruger      petsc_full_src = opts.srcdir
1936f5e9bd5SScott Kruger    if opts.testdir == 'tests':
1946f5e9bd5SScott Kruger      petsc_full_test = os.path.join(petsc_full_arch, 'tests')
1956f5e9bd5SScott Kruger    else:
1966f5e9bd5SScott Kruger      petsc_full_test = opts.testdir
1976f5e9bd5SScott Kruger    if opts.startdir:
1986f5e9bd5SScott Kruger      startdir=opts.startdir=petsc_full_src
1996f5e9bd5SScott Kruger    else:
2006f5e9bd5SScott Kruger      startdir=petsc_full_src
2016f5e9bd5SScott Kruger
2026f5e9bd5SScott Kruger    # Options Sanity checks
2036f5e9bd5SScott Kruger    if not os.path.isdir(petsc_dir):
2046f5e9bd5SScott Kruger        print("PETSC_DIR must be a directory")
2056f5e9bd5SScott Kruger        return
2066f5e9bd5SScott Kruger
2076f5e9bd5SScott Kruger    if not opts.use_source:
2086f5e9bd5SScott Kruger        if not os.path.isdir(petsc_full_arch):
2096f5e9bd5SScott Kruger            print("PETSC_DIR/PETSC_ARCH must be a directory")
2106f5e9bd5SScott Kruger            return
2116f5e9bd5SScott Kruger        elif not os.path.isdir(petsc_full_test):
2126f5e9bd5SScott Kruger            print("Testdir must be a directory"+petsc_full_test)
2136f5e9bd5SScott Kruger            return
2146f5e9bd5SScott Kruger    else:
2156f5e9bd5SScott Kruger        if not os.path.isdir(petsc_full_src):
2166f5e9bd5SScott Kruger            print("Source directory must be a directory"+petsc_full_src)
2176f5e9bd5SScott Kruger            return
2186f5e9bd5SScott Kruger
2196f5e9bd5SScott Kruger    # Do the actual query
2206f5e9bd5SScott Kruger    do_query(opts.use_source, startdir, petsc_full_src, petsc_full_test, field, match)
2216f5e9bd5SScott Kruger
2226f5e9bd5SScott Kruger    return
2236f5e9bd5SScott Kruger
2246f5e9bd5SScott Kruger
2256f5e9bd5SScott Krugerif __name__ == "__main__":
2266f5e9bd5SScott Kruger        main()
227