1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
3  * http://www.gnu.org/licenses/gpl-3.0.html
4  *
5  * $Revision: 9376 $
6  * $Id: cbprofiler.cpp 9376 2013-10-01 20:30:42Z fuscated $
7  * $HeadURL: svn://svn.code.sf.net/p/codeblocks/code/branches/release-20.xx/src/plugins/contrib/profiler/cbprofiler.cpp $
8  */
9 
10 #include "sdk.h"
11 #ifndef CB_PRECOMP
12     #include <wx/datetime.h>
13     #include <wx/filename.h>
14     #include <wx/fs_zip.h>
15     #include <wx/intl.h>
16     #include <wx/string.h>
17     #include <wx/xrc/xmlres.h>
18     #include "cbproject.h"
19     #include "configmanager.h"
20     #include "globals.h"
21     #include "macrosmanager.h"
22     #include "manager.h"
23     #include "logmanager.h"
24     #include "projectbuildtarget.h"
25     #include "projectmanager.h"
26 #endif
27 #include <wx/choicdlg.h>
28 #include <wx/filedlg.h>
29 #include "cbprofiler.h"
30 #include "cbprofilerconfig.h"
31 #include "cbprofilerexec.h"
32 #include "prep.h"
33 
34 // Register the plugin
35 namespace
36 {
37     PluginRegistrant<CBProfiler> reg(_T("Profiler"));
38 };
39 
CBProfiler()40 CBProfiler::CBProfiler()
41 {
42     //ctor
43     if(!Manager::LoadResource(_T("Profiler.zip")))
44     {
45         NotifyMissingFile(_T("Profiler.zip"));
46     }
47 }
48 
~CBProfiler()49 CBProfiler::~CBProfiler()
50 {
51     //dtor
52 }
53 
OnAttach()54 void CBProfiler::OnAttach()
55 {
56     // do whatever initialization you need for your plugin
57     // NOTE: after this function, the inherited member variable
58     // IsAttached() will be TRUE...
59     // You should check for it in other functions, because if it
60     // is FALSE, it means that the application did *not* "load"
61     // (see: does not need) this plugin...
62 }
63 
OnRelease(bool)64 void CBProfiler::OnRelease(bool /*appShutDown*/)
65 {
66     // do de-initialization for your plugin
67     // if appShutDown is false, the plugin is unloaded because Code::Blocks is being shut down,
68     // which means you must not use any of the SDK Managers
69     // NOTE: after this function, the inherited member variable
70     // IsAttached() will be FALSE...
71 }
72 
GetConfigurationPanel(wxWindow * parent)73 cbConfigurationPanel* CBProfiler::GetConfigurationPanel(wxWindow* parent)
74 {
75     // if not attached, exit
76     if (!IsAttached())
77         return 0;
78 
79     CBProfilerConfigDlg* dlg = new CBProfilerConfigDlg(parent);
80     return dlg;
81 }
82 
Execute()83 int CBProfiler::Execute()
84 {
85     // if not attached, exit
86     if (!IsAttached())
87         return -1;
88 
89     cbProject* project = Manager::Get()->GetProjectManager()->GetActiveProject();
90     // if no project open, exit
91     if (!project)
92     {
93         wxString msg = _("You need to open a project\nbefore using the plugin!\n"
94                          "C::B Profiler could not complete the operation.");
95         cbMessageBox(msg, _("Error"), wxICON_ERROR | wxOK, Manager::Get()->GetAppWindow());
96         Manager::Get()->GetLogManager()->DebugLog(msg);
97         return -1;
98     }
99 
100     ProjectBuildTarget* target = 0L;
101     if (project->GetBuildTargetsCount() > 1)
102     {
103         // more than one executable target? ask...
104         std::vector<wxString> choices(project->GetBuildTargetsCount());
105         wxString active_target = project->GetActiveBuildTarget();
106         int selected = 0;
107         for (int i=0; i<project->GetBuildTargetsCount(); ++i)
108         {
109             choices[i] = project->GetBuildTarget(i)->GetTitle();
110             if (choices[i] == active_target)
111                 selected = i;
112         }
113         wxSingleChoiceDialog dialog(Manager::Get()->GetAppWindow(),
114                                     _("Select the target you want to profile"),
115                                     _("Select Target"),
116                                     project->GetBuildTargetsCount(), &choices[0]);
117         dialog.SetSelection(selected);
118         if (dialog.ShowModal() != wxID_OK)
119             return -1;
120         int targetIndex = dialog.GetSelection();
121         target = project->GetBuildTarget(targetIndex);
122     }
123     else if (project->GetBuildTargetsCount() == 1)
124         target = project->GetBuildTarget(0);
125     else
126     {
127         // not even one executable target...
128         wxString msg = _("No executable targets found in project!\n"
129                          "C::B Profiler could not complete the operation.");
130         cbMessageBox(msg, _("Error"), wxICON_ERROR | wxOK, Manager::Get()->GetAppWindow());
131         Manager::Get()->GetLogManager()->DebugLog(msg);
132         return -1;
133     }
134 
135     if ((target->GetTargetType() != ttExecutable) && (target->GetTargetType() != ttConsoleOnly))
136     {
137         wxString msg = _("The target is not executable!");
138         cbMessageBox(msg, _("Error"), wxICON_ERROR | wxOK, Manager::Get()->GetAppWindow());
139         Manager::Get()->GetLogManager()->DebugLog(msg);
140         return -1;
141     }
142 
143     // Scope...
144     wxString exename,dataname;
145 
146     if (target)
147     {
148         exename = target->GetOutputFilename();
149         Manager::Get()->GetMacrosManager()->ReplaceEnvVars(exename);
150         wxFileName ename(exename);
151         ename.Normalize(wxPATH_NORM_ALL, project->GetBasePath());
152         exename = ename.GetFullPath();
153 
154         wxChar separator = wxFileName::GetPathSeparator();
155 
156         // The user either hasn't built the target yet or cleaned the project
157         if (!ename.FileExists())
158         {
159             wxString msg = _("No executable found!\n"
160                              "You either have not built the target or\n"
161                              "just cleaned the project.\n"
162                              "Try to find profiling info anyway?");
163             if (cbMessageBox(msg,_("Confirmation"),wxYES_NO | wxICON_QUESTION,
164                              Manager::Get()->GetAppWindow()) == wxID_NO)
165                 return -2;
166         }
167 
168         // We locate gmon.out. First: look for gmon.out in the folder of the executable
169         dataname=exename.BeforeLast(separator);
170         dataname+=separator;
171         dataname+=_T("gmon.out");
172         wxFileName dname(dataname);
173 
174         // The gmon.out file doesn't exist in the executable's directory.
175         if (!dname.FileExists())
176         {
177             // Second: look for gmon.out in the working directory of the project
178             wxString workname = target->GetWorkingDir();
179             Manager::Get()->GetMacrosManager()->ReplaceEnvVars(workname);
180             wxFileName wname(workname);
181             wname.Normalize(wxPATH_NORM_ALL, project->GetBasePath());
182             workname = wname.GetFullPath();
183 
184             dataname=workname.BeforeLast(separator);
185             dataname+=separator;
186             dataname+=_T("gmon.out");
187             dname = wxFileName(dataname);
188 
189             // The gmon.out file doesn't exist in the working directory.
190             if (!dname.FileExists())
191             {
192                 wxString msg = _("No profile data found!\n"
193                                  "Be sure to enable \"Profile Code when executed\" for the current target.\n"
194                                  "The target must have been run at least one time after that.\n"
195                                  "Do you want to search for the profile data file?");
196                 if (cbMessageBox(msg, _("Cannot find gmon.out."), wxICON_QUESTION | wxYES_NO, Manager::Get()->GetAppWindow()) == wxID_NO)
197                     return -1;
198                 else
199                 {
200                     wxFileDialog filedialog(Manager::Get()->GetAppWindow(), _("Locate profile information"),
201                                             _T(""),_T("gmon.out"),_T("*.*"),wxFD_OPEN|wxFD_FILE_MUST_EXIST|compatibility::wxHideReadonly);
202                     if (filedialog.ShowModal() == wxID_OK)
203                     {
204                         dataname = filedialog.GetPath();
205                         dname = wxFileName(dataname);
206                     }
207                     else return -1;
208                 }
209             }
210         }
211 
212         Manager::Get()->GetLogManager()->DebugLog(_("Using executable file from: ") + exename);
213         Manager::Get()->GetLogManager()->DebugLog(_("Using gmon.out   file from: ") + dataname);
214 
215         // If we got so far, it means both the executable and the profile data exist
216         wxDateTime exetime  = ename.GetModificationTime();
217         wxDateTime datatime = dname.GetModificationTime();
218 
219         // Profile data might be old...
220         if (exetime>datatime)
221         {
222             wxString msg = _("It seems like the profile data is older than the executable.\n"
223                              "You probably have not run the executable to update this data.\n"
224                              "Continue anyway?");
225             if (cbMessageBox(msg,_("Confirmation"),wxYES_NO | wxICON_QUESTION,
226                              Manager::Get()->GetAppWindow()) == wxID_NO)
227                 return -2;
228         }
229     }
230 
231     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("cbprofiler"));
232 
233     // Loading configuration
234     struct_config config;
235     config.chkAnnSource        = cfg->ReadBool(_T("/ann_source_chk"), false);
236     config.txtAnnSource        = cfg->Read(_T("/ann_source_txt"), wxEmptyString);
237     config.chkMinCount         = cfg->ReadBool(_T("/min_count_chk"), false);
238     config.spnMinCount         = cfg->ReadInt(_T("/min_count_spn"), 0);
239     config.chkBrief            = cfg->ReadBool(_T("/brief"), false);
240     config.chkFileInfo         = cfg->ReadBool(_T("/file_info"), false);
241     config.chkUnusedFunctions  = cfg->ReadBool(_T("/unused_functions"), false);
242     config.chkStaticCallGraph  = cfg->ReadBool(_T("/static_call_graph"), false);
243     config.chkNoStatic         = cfg->ReadBool(_T("/no_static"), false);
244     config.chkMinCount         = cfg->ReadBool(_T("/min_count_chk"), false);
245     config.chkSum              = cfg->ReadBool(_T("/sum"), false);
246     config.txtExtra            = cfg->Read(_T("/extra_txt"), wxEmptyString);
247 
248     // If we got this far, all is left is to call gprof!!!
249     dlg = new CBProfilerExecDlg(Manager::Get()->GetAppWindow());
250 
251     // Do we need to show the dialog (process succesful)?
252     if (dlg->Execute(exename, dataname, config) != 0)
253         return -1;
254 
255     return 0;
256 }
257