2009-05-21 22 views
1

任何人都知道腳本可以獲取一個列表,它可以告訴我C程序中最頻繁調用的函數嗎?創建列表的腳本:<Method Name><爲某個特定項目目錄調用次數>

方法1 391
方法2 23
方法3 12

更妙的是它具有可定製要求的方法名「得到」的關鍵詞。

我試圖不重新發明輪子,並寫一個簡單的腳本來自己做。用grep或awk做一個簡單的方法。我可以編寫一個正則表達式來匹配函數調用名稱。 Eclipse插件將是理想的。

我不是在尋找一個分析器。我想要這種方法的原因是我需要優化嵌入式項目的程序空間。我傾向於用getter封裝我的成員變量,但可能需要使用externs並直接訪問最常用的成員來減少空間。

+0

您使用的工具是什麼?許多會生成一個調用圖作爲輸出的一部分。 – Dingo 2009-05-21 11:16:58

+0

我正在使用HiTech PICC-18 STD。你說得對,我可以得到一個通話圖。我想這使得它稍微容易一些,因爲現在我在一個文件中擁有所有的信息......但是我仍然會使用一個簡單的腳本來創建彙總表。 – blak3r 2009-05-21 22:03:04

回答

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

一種方法是在源代碼上運行Doxygen。除非已經使用Doxygen,否則需要將其配置爲提取所有函數和類,因爲默認情況下它會忽略無證實體。

如果您還安裝了AT & T GraphViz,您可以爲每個功能繪製漂亮的調用圖和調用者圖。但我不認爲有一張表格按呼叫次數總結了這一點。

但是,可以選擇幾種非文檔輸出格式,包括Perl模塊和XML。應該可以解析其中的一個來開發你想要的列表,而解析這些信息幾乎肯定比分析足夠多的C++前端以通過暴力獲得正確答案更容易。

還有一個GCC的XML後端在某個地方浮動,基本上轉儲XML中的語法樹......我最近已經絆住了它,但不具體回憶那是什麼。

0

如果「最頻繁」意味着某些程序運行的實際呼叫次數,DTrace可能是您正在尋找的工具,假設您有用於開發工作的Solaris,FreeBSD或OSX框。請參閱Code Spelunking redux以獲得對Doxygen和DTrace的很好的描述。

相關問題