Script to create a list: <Method name> <Number of times called> for a specific project directory

Does anyone know a script to get a list that can tell me the most commonly called functions for a C project?

method1 391
method2 23
method3 12

Better yet, configure it to use the keyword in the "get" method name.

I am trying not to reinvent the wheel and write a simple script to do this myself. This is probably an easy way to do it using grep or awk. I can write a regex to match the name of a function call. An Eclipse plugin would be perfect.

I'm not looking for a profiler. The reason I need a method like this is to optimize the space for an embedded project. I tend to encapsulate my member variables with getters, but it may be necessary to use external elements and access the most commonly used elements to save space.

+1


source share


3 answers


Here is a simple java script that provides the output I was looking for. By setting up the two REGEX at the top of the file, it can be used to generate statistics on the occurrence of other patterns.



import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

public class MethodCallCount {
    // This is the regex which is applied to each line to test if there is a method call on it.
    private static String REGEX_METHODCALL = "(?:\\s*)([a-zA-Z0-9_]+)\\((.*)"; 
    // Only looks in files with .c extention
    private static String REGEX_FILEEXTS = ".*.c";
    private static boolean VERBOSE_OUTPUT = false;
    private static Map<String,Integer> patternMap = new HashMap<String,Integer>();

    // Process all files and directories under dir
    public static void visitAllDirsAndFiles(File dir) {

        if( !dir.isDirectory()) {
            if( dir.getName().matches(REGEX_FILEEXTS) ) {
                if( VERBOSE_OUTPUT ) { System.out.println("Processing File: " + dir.getName() ); }
                processFile(dir);
            }
        }
        else if( !dir.getName().equals(".svn") ) {
            String[] children = dir.list();
            for (int i=0; i<children.length; i++) {
                visitAllDirsAndFiles(new File(dir, children[i]));
            }
        }
    }

    // Process only directories under dir
    public static void visitAllDirs(File dir) {
        if (dir.isDirectory()) {
            processFile(dir);

            String[] children = dir.list();
            for (int i=0; i<children.length; i++) {
                visitAllDirs(new File(dir, children[i]));
            }
        }
    }

    // Process only files under dir
    public static void visitAllFiles(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (int i=0; i<children.length; i++) {
                visitAllFiles(new File(dir, children[i]));
            }
        } else {
            processFile(dir);
        }
    }

    public static void processMethod( String pMethod ) {
        if( VERBOSE_OUTPUT ) { System.out.println("found: " + pMethod); }
        if( patternMap.containsKey( pMethod ) ) {
            Integer cnt = patternMap.get( pMethod );
            cnt = cnt + 1;
            patternMap.put(pMethod, cnt );
        }
        else {
            patternMap.put( pMethod.toString(), 1);
        }       
    }


    public static void processLine( String pLine ) {
        Pattern methodMatcher = Pattern.compile( REGEX_METHODCALL );
        java.util.regex.Matcher matcher = methodMatcher.matcher( pLine );

        if( matcher.matches() ) {
            if( VERBOSE_OUTPUT ) { System.out.println("processing " + matcher.group(1) ); }
            processMethod( matcher.group(1) );                  
            processLine( matcher.group(2) );
        }
    }

    public static void processFile( File pFile ) {
        BufferedReader fin;
        try {
            fin = new BufferedReader( new InputStreamReader( new FileInputStream(pFile) ) );
            String l = null;
            while( (l=fin.readLine()) != null ) {
                processLine( l );
            }
        } 
        catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }       
    }

    /**
     * @param args[0] is the directory to run this on.  Otherwise current directory is used.
     */
    public static void main(String[] args) {

        String searchDirPath = System.getProperty("user.dir");
        if( args.length > 0 ) {
            searchDirPath = args[0];
        }
        else {
            System.out.println("No argument specified... searching for *.map in: " + searchDirPath );
        }

        File searchDir = new File( searchDirPath );
        visitAllDirsAndFiles(searchDir);

        // Print Stats.
        int callCnt = 0;
        Set<String> patternSet = patternMap.keySet();
        for( String p : patternSet ) {
            System.out.println( patternMap.get(p) + "\t" + p );
            callCnt += patternMap.get(p);
        }
        System.out.println("Unique Methods: " + patternMap.size());
        System.out.println("Calls Detected: " + callCnt );
        System.out.println("Copy and paste output above into excel and then sort columns");
        System.out.println("DONE.");
    }
}

      

+1


source


One approach is to run Doxygen from a source base. You will need to configure it to retrieve all functions and classes if you are not already using Doxygen, as it ignores undocumented objects by default.

If you also have AT&T GraphViz installed , you can get beautiful call and caller graphs for every feature. But I don't think there is a table that summarizes this by the number of calls.



However, there are several non-formatted output formats that can be chosen, including the Perl module and XML. It should be possible to parse one of these to develop the list you want, and it is almost certainly easier to parse this information than to hack enough of the C ++ interface to get a brute-force answer right.

There is also an XML backend for GCC floating around somewhere that essentially dumps the syntax tree in XML ... I stumbled over it recently but don't remember exactly where it was.

+1


source


If "most often" refers to the actual number of calls in a given program run, DTrace might be the tool you are if you have a Solaris, FreeBSD, or OSX window to develop. See also Code Spelunking redux for a nice description of Doxygen and DTrace.

0


source







All Articles