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