用于创建特定项目目录的<method name =“”> <number of =“”times =“”called =“”>的列表的脚本</num> </method>

时间:2009-05-21 07:13:11

标签: c statistics scripting

任何人都知道一个脚本来获取一个能够告诉我C项目最常被调用的函数的列表吗?

方法1 391
方法2 23
method3 12

更好的是,可以自定义方法名称“get”中的关键字。

我正在尝试不重新发明轮子并编写一个简单的脚本来自己完成。使用grep或awk可能是一种简单的方法。我可以编写一个正则表达式来匹配函数调用名称。 Eclipse插件是理想的。

我不是在寻找一个探查器。我想要这样一个方法的原因是我需要为嵌入式项目优化程序空间。我倾向于使用getter封装我的成员变量,但可能需要使用externs并直接访问最常用的成员以减少空间。

3 个答案:

答案 0 :(得分:1)

这是一个简单的java脚本,它提供了我正在寻找的输出。 通过自定义文件顶部的两个REGEX,它可以用于生成其他模式出现的统计数据。

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 :(得分:1)

一种方法是在源代码库上运行Doxygen。您需要将其配置为提取所有函数和类,除非您已经在使用Doxygen,因为默认情况下它会忽略未记录的实体。

如果你还安装了AT&amp; T GraphViz,你可以获得为每个功能绘制的漂亮的呼叫和来电图。但我不认为有一个表格可以通过呼叫数量来概括。

但是,可以选择几种非文档输出格式,包括Perl模块和XML。应该可以解析其中一个来开发你想要的列表,解析这些信息几乎肯定比通过破解足够的C ++前端来蛮力得到正确的答案更容易。

还有一个GCC的XML后端漂浮在某处,基本上以XML格式转储语法树...我最近绊倒了它,但不记得具体在哪里。

答案 2 :(得分:0)

如果“最频繁”是指程序的某些运行中的实际调用次数,DTrace可能是您正在寻找的工具,假设您有用于开发工作的Solaris,FreeBSD或OSX框。另请参阅Code Spelunking redux以获取有关Doxygen和DTrace的详细说明。