Пример #1
0
void CallGraph::OnShowCallGraph(wxCommandEvent& event)
{
    // myLog("wxThread::IsMain(%d)", (int)wxThread::IsMain());

    IConfigTool* config_tool = m_mgr->GetConfigTool();
    MacroManager* macro = MacroManager::Instance();
    wxASSERT(macro);

    config_tool->ReadObject(wxT("CallGraph"), &confData);

    if(!wxFileExists(GetGprofPath()) || !wxFileExists(GetDotPath()))
        return MessageBox(_T("Failed to locate required tools (gprof, dot). Please check the plugin settings."),
                          wxICON_ERROR);

    clCxxWorkspace* ws = m_mgr->GetWorkspace();
    if(!ws) return MessageBox(_("Unable to get opened workspace."), wxICON_ERROR);

    wxFileName ws_cfn = ws->GetWorkspaceFileName();

    wxString projectName = ws->GetActiveProjectName();
    
    wxString errMsg;
    ProjectPtr proj = ws->FindProjectByName( projectName, errMsg );
    wxString projPath = proj->GetProjectPath();

    BuildMatrixPtr mtx = ws->GetBuildMatrix();
    if(!mtx) return MessageBox(_("Unable to get current build matrix."), wxICON_ERROR);

    wxString build_config_name = mtx->GetSelectedConfigurationName();

    BuildConfigPtr bldConf = ws->GetProjBuildConf(projectName, build_config_name);
    if(!bldConf) return MessageBox(_("Unable to get opened workspace."), wxICON_ERROR);

    wxString projOutputFn = macro->Expand( bldConf->GetOutputFileName(), m_mgr, projectName, build_config_name );
    #ifdef __WXMSW__
    if( ! projOutputFn.Lower().EndsWith( wxT(".exe") ) ) projOutputFn += wxT(".exe");
    #endif //__WXMSW__

//    myLog("WorkspaceFileName = \"%s\"", ws_cfn.GetFullPath());
//    myLog("projectName \"%s\"", projectName);
//    myLog("build_config_name = \"%s\"", build_config_name);
//    myLog("projOutputFn = \"%s\"", projOutputFn);
//    myLog("projPath = \"%s\"", projPath);

    wxFileName cfn(projPath + wxFileName::GetPathSeparator() + projOutputFn);
    cfn.Normalize();

    // base path
    const wxString base_path = ws_cfn.GetPath();

    // check source binary exists
    wxString bin_fpath = cfn.GetFullPath();
    if(!cfn.Exists()) {
        bin_fpath = wxFileSelector("Please select the binary to analyze", base_path, "", "");
        if(bin_fpath.IsEmpty()) return MessageBox("selected binary was canceled", wxICON_ERROR);

        cfn.Assign(bin_fpath, wxPATH_NATIVE);
    }
    if(!cfn.IsFileExecutable()) return MessageBox("bin/exe isn't executable", wxICON_ERROR);

    // check 'gmon.out' file exists
    wxFileName gmon_cfn( cfn.GetPath() + wxFileName::GetPathSeparator() + GMON_FILENAME_OUT);
    gmon_cfn.Normalize();

    wxString gmonfn = gmon_cfn.GetFullPath();
    if(!gmon_cfn.Exists()) {
        gmonfn = wxFileSelector("Please select the gprof file", gmon_cfn.GetPath(), "gmon", "out");
        if(gmonfn.IsEmpty()) return MessageBox("selected gprof was canceled", wxICON_ERROR);

        gmon_cfn.Assign(gmonfn, wxPATH_NATIVE);
    }

    wxString bin, arg1, arg2;

    bin = GetGprofPath();
    arg1 = bin_fpath;
    arg2 = gmonfn;

    wxString cmdgprof = wxString::Format("%s %s %s", bin, arg1, arg2);

    // myLog("about to wxExecute(\"%s\")", cmdgprof);

    wxProcess* proc = new wxProcess(wxPROCESS_REDIRECT);

    // wxStopWatch	sw;

    const int err = ::wxExecute(cmdgprof, wxEXEC_SYNC, proc);
    // on sync returns 0 (success), -1 (failure / "couldn't be started")

    // myLog("wxExecute() returned err %d, had pid %d", err, (int)proc->GetPid());

    wxInputStream* process_is = proc->GetInputStream();
    if(!process_is || !process_is->CanRead())
        return MessageBox(_("wxProcess::GetInputStream() can't be opened, aborting"), wxICON_ERROR);

    // start parsing and writing to dot language file
    GprofParser pgp;

    pgp.GprofParserStream(process_is);

    // myLog("gprof done (read %d lines)", (int) pgp.lines.GetCount());

    delete proc;

    ConfCallGraph conf;

    config_tool->ReadObject(wxT("CallGraph"), &conf);

    DotWriter dotWriter;

    // DotWriter
    dotWriter.SetLineParser(&(pgp.lines));

    int suggestedThreshold = pgp.GetSuggestedNodeThreshold();

    if(suggestedThreshold <= conf.GetTresholdNode()) {
        suggestedThreshold = conf.GetTresholdNode();

        dotWriter.SetDotWriterFromDialogSettings(m_mgr);

    } else {
        dotWriter.SetDotWriterFromDetails(conf.GetColorsNode(),
                                          conf.GetColorsEdge(),
                                          suggestedThreshold,
                                          conf.GetTresholdEdge(),
                                          conf.GetHideParams(),
                                          conf.GetStripParams(),
                                          conf.GetHideNamespaces());

        wxString suggest_msg = wxString::Format(_("The CallGraph plugin has suggested node threshold %d to speed-up "
                                                  "the call graph creation. You can alter it on the call graph panel."),
                                                suggestedThreshold);

        MessageBox(suggest_msg, wxICON_INFORMATION);
    }

    dotWriter.WriteToDotLanguage();

    // build output dir
    cfn.Assign(base_path, "");
    cfn.AppendDir(CALLGRAPH_DIR);
    cfn.Normalize();

    if(!cfn.DirExists()) cfn.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);

    cfn.SetFullName(DOT_FILENAME_TXT);
    wxString dot_fn = cfn.GetFullPath();

    dotWriter.SendToDotAppOutputDirectory(dot_fn);

    cfn.SetFullName(DOT_FILENAME_PNG);
    wxString output_png_fn = cfn.GetFullPath();

    // delete any existing PNG
    if(wxFileExists(output_png_fn)) wxRemoveFile(output_png_fn);

    wxString cmddot_ln;

    cmddot_ln << GetDotPath() << " -Tpng -o" << output_png_fn << " " << dot_fn;

    // myLog("wxExecute(\"%s\")", cmddot_ln);

    wxExecute(cmddot_ln, wxEXEC_SYNC | wxEXEC_HIDE_CONSOLE);

    // myLog("dot done");

    if(!wxFileExists(output_png_fn))
        return MessageBox(_("Failed to open file CallGraph.png. Please check the project settings, rebuild the project "
                            "and try again."),
                          wxICON_INFORMATION);

    // show image and create table in the editor tab page
    uicallgraphpanel* panel = new uicallgraphpanel(
        m_mgr->GetEditorPaneNotebook(), m_mgr, output_png_fn, base_path, suggestedThreshold, &(pgp.lines));

    wxString tstamp = wxDateTime::Now().Format(wxT(" %Y-%m-%d %H:%M:%S"));

    wxString title = wxT("Call graph for \"") + output_png_fn + wxT("\" " + tstamp);

    m_mgr->AddEditorPage(panel, title);
}