2009-09-18 28 views
5

Tôi đã thừa hưởng một codebase khá lớn, 90% C++ và tôi cần phải tăng tốc độ nhanh chóng. Có hàng trăm tệp .cc trong cấu trúc cây thư mục rộng.Kịch bản để chèn đăng nhập vào mọi chức năng trong một dự án?

Nó khá phức tạp và không có ghi nhật ký. Để tìm ra cách một số hệ thống con chính hoạt động, tôi muốn chèn một lời gọi hàm vào mọi hàm.

Ví dụ, cho một tập tin .cc đầy đủ những thứ như thế này:

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

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

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

Tôi muốn có được điều này:

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."; 
    // ... 
} 

này có thể được thực hiện thông qua kịch bản python, CMD kịch bản, kịch bản vỏ nguồn, v.v. Nếu có một cách để làm cho VS làm điều đó, tuyệt vời. Dù có hiệu quả. Không cần phải xinh đẹp, tôi không kiểm tra bất kỳ điều gì trong số này.

Ngoài ra, nó không nhất thiết phải có mọi thứ. Ví dụ. các lớp lồng nhau, triển khai trong tệp tiêu đề, v.v.

Trả lời

4

Đã một cái gì đó tương tự cho thêm mã hồ sơ sử dụng Macros trong VS, đây là mã (điều này nhóm cũng tất cả mọi thứ dưới một single "undo" lệnh và liệt kê tất cả những thay đổi trong cửa sổ đầu ra riêng của mình)

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 Hãy nhớ để thay đổi "Const ToInsert As string = ..." vào mã bạn thực sự muốn được chèn

+0

Đây là một cách tiếp cận thú vị! +1.Tôi sẽ đặt cược rằng VS IDE làm một công việc tốt hơn để khám phá sự khởi đầu của các định nghĩa chức năng hơn là một regex được xây dựng bằng tay. Nhưng giả sử "CodeModel" giống như IntelliSense sử dụng, có một vài trường hợp nó vẫn sẽ bị nghẹt thở trong kinh nghiệm của tôi. –

+0

Điều này khá tiện lợi. Tôi sẽ cho nó một viên đạn. –

+0

Có cách nào để loại trừ các tệp tiêu đề (.h và .inl) không? Ngoài ra, có lẽ loại trừ các mẫu? –

1

Trình hồ sơ thời gian chạy sẽ cung cấp cho bạn thông tin đó: nó sẽ cho biết các chương trình con được gọi từ mỗi thường trình và bao nhiêu lần (nhưng không theo thứ tự nào) .

+0

Yeah, tôi đã thử một loạt các profilers (miễn phí) khác nhau, trong đó có một từ Microsoft. Hoặc là tất cả họ hút hoặc tôi quá ngu ngốc để tìm ra cách sử dụng chúng. Nếu bạn có một liên kết đến một công cụ phong nha và một số hướng dẫn về cách để có được những thông tin trên bạn hứa hẹn, tôi sẽ sẵn sàng cho nó một đi. Tại thời điểm này nó chỉ có vẻ dễ dàng hơn để chèn một số đăng nhập. –

+1

Tôi đã không sử dụng một trong độ tuổi. Một trong những tôi đã sử dụng (từ Numega) đã được bán (để Compuware), và sau đó bán lại bây giờ thuộc sở hữu của "Micro Focus": http://www.microfocus.com/products/DevPartner/StudioProfessionalEditionCapabilities.asp#6 trang web của họ nói rằng bạn có thể tải xuống phiên bản dùng thử của nó. – ChrisW

2

Tôi đã làm điều đó một vài năm trước đây trong VS.
Regex sẽ giúp bạn.
BTW, nó không nesasary để chèn chuỗi khác nhau. Bạn có thể thêm cùng một chuỗi như:


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

EDIT

cái gì đó như regexp này (có giá trị cho chỉ VS):


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

Bạn nên mở rộng regexp phụ thuộc vào nhu cầu của bạn.

+0

Có, __FUNCTION __... điểm tốt. Bạn sẽ không xảy ra để có một regex phong nha nửa chừng, phải không? –

+0

@jeffamaphone: Tôi thêm mẫu regexp vào câu trả lời của tôi – Dmitriy

+0

Điều này có thể hoạt động nếu tất cả các khai báo hàm của bạn theo một mẫu đơn giản, nhưng nó không thể bắt tất cả các hàm trong một codebase lớn, phức tạp. (một số khó phân biệt với các kiểu khai báo khác). –

1

Bạn đã xem xét chạy mã trong trình gỡ lỗi và chỉ cần duyệt qua toàn bộ ứng dụng (hoặc đặt một điểm ngắt trên mã bạn quan tâm và chỉ cần thực hiện bước đó)? Tôi thấy rằng đôi khi là một kỹ thuật hữu ích khi phải đối mặt với một cơ sở mã di sản lớn mà tôi không viết.

Ngoài ra, nếu bạn đang biên dịch trong thế giới VS, hãy xem xét xem các công tắc /Gh/GH chuyển sang cl.exe. Họ dường như cho phép bạn móc nhập/thoát chức năng và gọi một số thói quen khác. Tôi chưa bao giờ sử dụng chúng trước đây, nhưng chúng dường như trực tiếp giải quyết nhu cầu của bạn.

+0

Ồ vâng, tôi làm điều đó cả ngày. Chỉ có rất nhiều công cụ không đồng bộ, đa luồng đang diễn ra và tôi đang tìm cách có được bức tranh cấp cao hơn về cách hoạt động của tính năng này. –

4

Vì bạn đang sử dụng Visual C++, và có vẻ như bạn chỉ cần tên của hàm được gọi, nó có thể là khả năng tự động này hơn nữa bằng cách sử dụng dòng lệnh sau chuyển sang cl.exe:

  • /Gh : Kích hoạt _penter chức năng gọi
  • /GH: Enable _pexit chức năng gọi

về cơ bản, cung cấp những công tắc có nghĩa là trình biên dịch sẽ tự động ly tiêm cuộc gọi đến các chức năng có tên _penter()_pexit() bất cứ khi nào bất kỳ chức năng nào bắt đầu hoặc kết thúc. Sau đó, bạn có thể cung cấp một mô-đun được biên dịch riêng để thực hiện hai hàm này, (a) gọi một số thư viện trợ giúp như DbgHelp để xác định tên của hàm được gọi hoặc (b) chỉ lấy địa chỉ trả về từ ngăn xếp và bản in nó đúng nguyên văn - sau đó, viết một kịch bản để chuyển đổi các địa chỉ này thành các tên hàm bằng cách xem ví dụ tệp bản đồ liên kết được tạo nếu bạn vượt qua /link /MAP:mymapfile.txt đến cl.exe.

Tất nhiên, bạn cần phải đặt _penter()_pexit() trong mô-đun riêng biệt với /Gh/GH bị tắt để tránh đệ quy vô hạn! :)

+0

Xin chào, điều đó có thể thú vị. Cảm ơn. –

+1

Bạn không cần một mô-đun riêng biệt cho các chức năng prolog/epilog. Cả hai hàm '_penter()' và '_pexit()' sẽ được định nghĩa như sau: 'extern' C 'void __declspec (naked) _cdecl _penter (void)'. Naked chức năng không phải là instrumented vì vậy không có cơ hội đệ quy. Bạn phải lo lắng về đệ quy về các hàm trẻ em nhưng có thể được giải quyết bằng cách sử dụng một biến cục bộ để kiểm tra sớm trong _penter() và _pexit() trước khi gọi bất kỳ con nào. – Adisak

Các vấn đề liên quan