2009-09-18 8 views
5

かなり大きなコードベース、90%C++を継承しました。私はそれを素早くスピードアップする必要があります。ワイドなディレクトリツリー構造には何百もの.ccファイルがあります。プロジェクトのすべての機能にログインするためのスクリプト?

これはかなり複雑で、ログはありません。いくつかの主要なサブシステムがどのように機能するかを理解するために、私はすべての関数に関数呼び出しを挿入したい。

例えば、このようなものの完全なの.ccファイル与えられた:私はこれを取得したいのですが

void A::foo(int a, int b) { 
    // ... 
} 

void A::bar() { 
    // ... 
} 

void B::bleh(const string& in) { 
    // ... 
} 

を:

void A::foo(int a, int b) { 
    LOG(debug) << "A::foo() called."; 
    // ... 
} 

void A::bar() { 
    LOG(debug) << "A::bar() called."; 
    // ... 
} 

void B::bleh(const string& in) { 
    LOG(debug) << "B::bleh() called."; 
    // ... 
} 

これは、Pythonスクリプト、CMDスクリプトを介して行うことができ、パワーシェルスクリプトなどがあります。もしそれをVSにする方法があれば、素晴らしい。どんな作品でも。かわいらしくなくてもいいのですが、これをチェックしていません。

また、必ずしもすべてを取得する必要はありません。例えば。ネストされたクラス、ヘッダファイル内の実装など

答えて

4

はVSでマクロを使用してプロファイリングコードを追加するための同様のものを持っていた:)、ここにコード (シングル「元に戻す」コマンドとリストの下で、このもグループすべてが独自の出力ウィンドウの変化のすべて)です

Imports System 
Imports EnvDTE 
Imports EnvDTE80 
Imports System.Diagnostics 

Public Module Module1 

    Function GetOutputWindowPane(ByVal Name As String, Optional ByVal show As Boolean = True) As OutputWindowPane 
     Dim window As Window 
     Dim outputWindow As OutputWindow 
     Dim outputWindowPane As OutputWindowPane 

     window = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput) 
     If show Then window.Visible = True 
     outputWindow = window.Object 
     Try 
      outputWindowPane = outputWindow.OutputWindowPanes.Item(Name) 
     Catch e As System.Exception 
      outputWindowPane = outputWindow.OutputWindowPanes.Add(Name) 
     End Try 
     outputWindowPane.Activate() 
     Return outputWindowPane 
    End Function 

    Const ToInsert As String = "/* Inserted text :D */" 

    Sub AddProfilingToFunction(ByVal func As CodeFunction2) 
     Dim editPoint As EditPoint2 = func.StartPoint.CreateEditPoint() 
     While editPoint.GetText(1) <> "{" 
      editPoint.CharRight() 
     End While 

     editPoint.CharRight() 
     editPoint.InsertNewLine(1) 

     Dim insertStartLine As Integer = editPoint.Line 
     Dim insertStartChar As Integer = editPoint.LineCharOffset 
     editPoint.Insert(ToInsert) 

     GetOutputWindowPane("Macro Inserted Code").OutputString(_ 
      editPoint.Parent.Parent.FullName & _ 
      "(" & insertStartLine & "," & insertStartChar & _ 
      ") : Inserted Code """ & ToInsert & """" & vbCrLf) 
    End Sub 

    Sub AddProfilingToProject(ByVal proj As Project) 
     If Not proj.CodeModel() Is Nothing Then 
      Dim EventTitle As String = "Add Profiling to project '" & proj.Name & "'" 
      GetOutputWindowPane("Macro Inserted Code").OutputString("Add Profiling to project '" & proj.Name & "'" & vbCrLf) 
      DTE.UndoContext.Open(EventTitle) 
      Try 
       Dim allNames As String = "" 
       For i As Integer = 1 To proj.CodeModel().CodeElements.Count() 
        If proj.CodeModel().CodeElements.Item(i).Kind = vsCMElement.vsCMElementFunction Then 
         AddProfilingToFunction(proj.CodeModel().CodeElements.Item(i)) 
        End If 
       Next 
      Finally 
       DTE.UndoContext.Close() 
      End Try 
      GetOutputWindowPane("Macro Inserted Code").OutputString(vbCrLf) 
     End If 
    End Sub 

    Sub AddProfilingToSolution() 
     GetOutputWindowPane("Macro Inserted Code").Clear() 
     If Not DTE.Solution Is Nothing And DTE.Solution.IsOpen() Then 
      For i As Integer = 1 To DTE.Solution.Projects.Count() 
       AddProfilingToProject(DTE.Solution.Projects.Item(i)) 
      Next 
     End If 
    End Sub 

End Module 

PS は、あなたが実際に

+0

これは興味深いアプローチです! +1。私は、VS IDEが、手作りの正規表現よりも関数定義の始まりを発見する優れた仕事をすると確信しています。しかし、 "CodeModel"がIntelliSenseの使用と同じものであると仮定すると、私の経験ではまだそれが詰まる場合があります。 –

+0

これはかなり元気です。私はそれを撃つだろう。 –

+0

ヘッダーファイル(.hと.inl)を除外する方法はありますか?また、おそらくテンプレートを除外しますか? –

1

実行時プロファイラは、どのようなサブルーチンが各ルーチンから呼び出されたか、何回(どのシーケンスではないか) 。

+0

はええ、私はからのものを含め、異なる(無料)プロファイラの束を試した挿入したいコードに「= ...文字列としてのConst ToInsert」に変更することを忘れないでくださいマイクロソフト彼らはすべて吸うか、私はあまりにも愚かで、どのようにそれらを使うかを理解する。まともなツールへのリンクがあり、上記の情報を得る方法に関するいくつかの指示がある場合は、それを喜んで提供します。この時点で、いくつかのロギングを挿入するほうが簡単です。 –

+1

私は年齢の中で使っていません。私が使用したもの(Numegaから)は(Compuwareへ)販売され、現在は「Micro Focus」によって所有されています。http://www.microfocus.com/products/DevPartner/StudioProfessionalEditionCapabilities.asp#6彼らのウェブサイトあなたが試用版をダウンロードできると言っています。 – ChrisW

2

私はVSで数年前にそれをしました。
正規表現がお手伝いします。
ところで、別の文字列を挿入するのはネサリではありません。


LOG(debug) << __FUNCTION__ << " called."; 

EDIT(のみVS有効)この正規表現のような

何か:


(void|char|int):b+:i\:\::i\([^(]*\):b*\{ 

あなたは、あなたのニーズに依存する正規表現を拡張する必要がありますが、あなたは次のように同じ文字列を追加することができます。

+0

ああ、__FUNCTION __...良い点。途中でまともな正規表現をしていないだろうか? –

+0

@jeffamaphone:私の答えに正規表現のサンプルを追加する – Dmitriy

+0

これは、関数宣言のすべてが単純なパターンに従うならば、これはうまくいくかもしれませんが、関数宣言は非常に珍しい形式を取ることができるので、 (そのうちのいくつかは他のタイプの宣言と区別するのが難しい)。 –

1

デバッガ内でコードを実行し、アプリケーション全体をステップ実行することを検討したことがありますか?そうでない場合は、目的のコードにブレークポイントを設定してそのステップを実行するだけですか?私はそれが、私が書いていない大きなレガシーコードベースに直面したときに、時には役に立つテクニックであることがわかります。

あなたはVSの世界でコンパイルしている場合あるいは、cl.exeから/Gh/GHスイッチの一覧を見てとることを検討してください。彼らはあなたが関数の入力/終了をフックし、他のルーチンを呼び出すことができるようです。私は以前はそれらを使ったことはありませんが、あなたのニーズに直接対応しているようです。

+0

ああ、私は一日中それをします。非同期でマルチスレッドのものがたくさんありますが、私はこのことがどのように機能するかをより高いレベルで把握したいと考えています。 –

4

は、Visual C++を使用している、そしてあなただけ呼び出される関数の名前を必要とすると思われるので、さらに、次のコマンドラインを使用して、これを自動化することができるかもしれないcl.exeに切り替わり:

  • /Gh :関数呼び出し_penter
  • /GH有効:基本的に_pexit関数呼び出し

を有効にし、これらのスイッチを提供することは、コンパイラが自動的なことを意味します機能の開始時または終了時に、_penter()および_pexit()という名前の関数への呼び出しを注入します。 (a)呼び出された関数の名前を調べるためにDbgHelpのような何らかのヘルパーライブラリを呼び出すか、(b)スタックから戻りアドレスを取得して印刷するかのどちらかを実行する、別々にコンパイルされたモジュールを提供することができますそれをそのまま言います - 後で、例えばこれらのアドレスを関数名に変換するためのスクリプトを書いてください/link /MAP:mymapfile.txtcl.exeに渡すと生成されるリンカーマップファイル。もちろん

、あなたは/Gh/GHは無限の再帰を避けるためにオフにして、別のモジュールであなたの_penter()_pexit()を配置する必要があります!

+0

ねえ、楽しいかもしれません。ありがとう。 –

+1

prolog/epilog機能のために別のモジュールは必要ありません。 '_penter()'と '_pexit()'の両方の関数は、 'extern "C" void __declspec(naked)_cdecl _penter(void) "のように定義されます。裸の関数は計装されていないので、再帰の可能性はありません。子関数の再帰を心配する必要はありますが、子を呼び出す前に_penter()および_pexit()で早期にスレッドローカル変数チェックを使用して解決できます。 – Adisak

関連する問題