[nemiver/profiler: 6/16] Start the profiler of a program from the UI



commit fe60a5871b2179c358a91879790f1088c2f06266
Author: Fabien Parent <parent f gmail com>
Date:   Sun Jun 17 10:00:37 2012 +0200

    Start the profiler of a program from the UI

 src/common/nmv-proc-utils.cc                       |   16 +-
 src/common/nmv-proc-utils.h                        |    4 +-
 src/persp/profperspective/menus/menus.xml          |    2 +
 src/persp/profperspective/nmv-prof-perspective.cc  |   69 ++++
 .../profperspective/nmv-run-program-dialog.cc      |  303 ++++++++++++++++++
 src/persp/profperspective/nmv-run-program-dialog.h |   69 ++++
 src/persp/profperspective/ui/Makefile.am           |    3 +-
 src/persp/profperspective/ui/runprogramdialog.ui   |  329 ++++++++++++++++++++
 src/profengine/nmv-i-profiler.h                    |    8 +
 src/profengine/nmv-perf-engine.cc                  |   66 ++++
 src/profengine/nmv-perf-engine.h                   |    6 +-
 11 files changed, 871 insertions(+), 4 deletions(-)
---
diff --git a/src/common/nmv-proc-utils.cc b/src/common/nmv-proc-utils.cc
index c6fc315..3f05c25 100644
--- a/src/common/nmv-proc-utils.cc
+++ b/src/common/nmv-proc-utils.cc
@@ -57,7 +57,8 @@ launch_program (const std::vector<UString> &a_args,
                 int &a_pid,
                 int &a_master_pty_fd,
                 int &a_stdout_fd,
-                int &a_stderr_fd)
+                int &a_stderr_fd,
+                const std::vector<UString> &a_environments)
 {
     RETURN_VAL_IF_FAIL (!a_args.empty (), false);
 
@@ -145,6 +146,19 @@ launch_program (const std::vector<UString> &a_args,
             const_cast<char*> (a_args[i].c_str ());
         }
 
+        std::auto_ptr<char *> environments;
+        environments.reset (new char* [a_environments.size () + 1]);
+        memset (environments.get (), 0,
+                sizeof (char*) * (a_environments.size () + 1));
+        if (!environments.get ()) {
+            exit (-1);
+        }
+
+        for (i = 0; i < a_environments.size (); ++i) {
+            environments.get ()[i] =
+            const_cast<char*> (a_environments[i].c_str ());
+        }
+
         execvp (args.get ()[0], args.get ());
         exit (-1);
     } else if (pid > 0) {
diff --git a/src/common/nmv-proc-utils.h b/src/common/nmv-proc-utils.h
index 6fd8497..6dc8091 100644
--- a/src/common/nmv-proc-utils.h
+++ b/src/common/nmv-proc-utils.h
@@ -36,7 +36,9 @@ bool NEMIVER_API launch_program (const std::vector<UString> &a_args,
                                  int &a_pid,
                                  int &a_master_pty_fd,
                                  int &a_stdout_fd,
-                                 int &a_stderr_fd);
+                                 int &a_stderr_fd,
+                                 const std::vector<UString> &a_environments
+                                     = std::vector<UString> ());
 
 void NEMIVER_API attach_channel_to_loop_context_as_source
                         (Glib::IOCondition a_cond,
diff --git a/src/persp/profperspective/menus/menus.xml b/src/persp/profperspective/menus/menus.xml
index 940a2be..0714b73 100644
--- a/src/persp/profperspective/menus/menus.xml
+++ b/src/persp/profperspective/menus/menus.xml
@@ -3,6 +3,8 @@
   <menubar name="MenuBar">
     <menu action="FileMenuAction" name="FileMenu">
         <placeholder name="FileMenuAdditions">
+            <menuitem action="RunExecutableAction"
+                      name="RunExecutableItem"/>
             <menuitem action="LoadReportMenuItemAction"
                       name="LoadReportMenuItem"/>
         </placeholder>
diff --git a/src/persp/profperspective/nmv-prof-perspective.cc b/src/persp/profperspective/nmv-prof-perspective.cc
index 51e403c..a353921 100644
--- a/src/persp/profperspective/nmv-prof-perspective.cc
+++ b/src/persp/profperspective/nmv-prof-perspective.cc
@@ -28,7 +28,9 @@
 #include "nmv-load-report-dialog.h"
 #include "nmv-call-list.h"
 #include "nmv-spinner-tool-item.h"
+#include "nmv-run-program-dialog.h"
 #include "common/nmv-safe-ptr-utils.h"
+#include "common/nmv-str-utils.h"
 
 #include <list>
 #include <glib/gi18n.h>
@@ -97,9 +99,14 @@ public:
     void init_body ();
     void load_report_file ();
     void load_report_file (const UString &a_report_file);
+    void run_executable ();
+    void run_executable (const UString &a_program_name,
+                         const UString &a_arguments);
 
+    void on_run_executable_action ();
     void on_load_report_file_action ();
     void on_report_done_signal (CallGraphSafePtr a_call_graph);
+    void on_record_done_signal (const UString &a_report_file);
 
     IProfilerSafePtr& profiler ();
 
@@ -252,6 +259,9 @@ ProfPerspective::init_signals ()
     THROW_IF_FAIL (profiler ());
     profiler ()->report_done_signal ().connect (sigc::mem_fun
         (*this, &ProfPerspective::on_report_done_signal));
+
+    profiler ()->record_done_signal ().connect (sigc::mem_fun
+        (*this, &ProfPerspective::on_record_done_signal));
 }
 
 void
@@ -278,6 +288,17 @@ ProfPerspective::on_report_done_signal (CallGraphSafePtr a_call_graph)
 }
 
 void
+ProfPerspective::on_record_done_signal (const UString &a_report_path)
+{
+    NEMIVER_TRY
+
+    THROW_IF_FAIL (profiler ());
+    profiler ()->report (a_report_path);
+
+    NEMIVER_CATCH
+}
+
+void
 ProfPerspective::init_actions ()
 {
     Gtk::StockID nil_stock_id ("");
@@ -285,6 +306,16 @@ ProfPerspective::init_actions ()
 
     static ui_utils::ActionEntry s_default_action_entries [] = {
         {
+            "RunExecutableAction",
+            nil_stock_id,
+            _("Run Executable..."),
+            _("Execute a program under the profiler"),
+            sigc::mem_fun (*this, &ProfPerspective::on_run_executable_action),
+            ui_utils::ActionEntry::DEFAULT,
+            "",
+            false
+        },
+        {
             "LoadReportMenuItemAction",
             nil_stock_id,
             _("_Load Report File..."),
@@ -330,6 +361,34 @@ ProfPerspective::edit_workbench_menu ()
 }
 
 void
+ProfPerspective::run_executable ()
+{
+    RunProgramDialog dialog (plugin_path ());
+
+    int result = dialog.run ();
+    if (result != Gtk::RESPONSE_OK) {
+        return;
+    }
+
+    run_executable (dialog.program_name (), dialog.arguments ());
+}
+
+void
+ProfPerspective::run_executable (const UString &a_program_name,
+                                 const UString &a_arguments)
+{
+    std::vector<UString> argv = str_utils::split (a_arguments, " ");
+
+    THROW_IF_FAIL (!a_program_name.empty ());
+    THROW_IF_FAIL (profiler ());
+
+    profiler ()->record (a_program_name, argv);
+
+    THROW_IF_FAIL (throbber);
+    throbber->start ();
+}
+
+void
 ProfPerspective::load_report_file (const UString &a_report_file)
 {
     THROW_IF_FAIL (!a_report_file.empty ());
@@ -365,6 +424,16 @@ ProfPerspective::on_load_report_file_action ()
     NEMIVER_CATCH
 }
 
+void
+ProfPerspective::on_run_executable_action ()
+{
+    NEMIVER_TRY
+
+    run_executable ();
+
+    NEMIVER_CATCH
+}
+
 Gtk::Widget*
 ProfPerspective::load_menu (const UString &/*a_filename*/, const UString &/*a_widget_name*/)
 {
diff --git a/src/persp/profperspective/nmv-run-program-dialog.cc b/src/persp/profperspective/nmv-run-program-dialog.cc
new file mode 100644
index 0000000..562c330
--- /dev/null
+++ b/src/persp/profperspective/nmv-run-program-dialog.cc
@@ -0,0 +1,303 @@
+//Author: Dodji Seketeli
+/*
+ *This file is part of the Nemiver project
+ *
+ *Nemiver is free software; you can redistribute
+ *it and/or modify it under the terms of
+ *the GNU General Public License as published by the
+ *Free Software Foundation; either version 2,
+ *or (at your option) any later version.
+ *
+ *Nemiver is distributed in the hope that it will
+ *be useful, but WITHOUT ANY WARRANTY;
+ *without even the implied warranty of
+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *See the GNU General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with Nemiver;
+ *see the file COPYING.
+ *If not, write to the Free Software Foundation,
+ *Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *See COPYRIGHT file copyright information.
+ */
+#include "config.h"
+#include <vector>
+#include <iostream>
+#include <glib/gi18n.h>
+#include <gtkmm/dialog.h>
+#include <gtkmm/entry.h>
+#include <gtkmm/filechooserbutton.h>
+#include <gtkmm/stock.h>
+#include <gtkmm/treeview.h>
+#include <gtkmm/liststore.h>
+#include "common/nmv-exception.h"
+#include "common/nmv-env.h"
+#include "common/nmv-ustring.h"
+#include "nmv-run-program-dialog.h"
+#include "nmv-ui-utils.h"
+
+using namespace std;
+using namespace nemiver::common;
+
+namespace nemiver {
+
+struct EnvVarModelColumns : public Gtk::TreeModel::ColumnRecord
+{
+    // I tried using UString here, but it didn't want to compile... jmj
+    Gtk::TreeModelColumn<Glib::ustring> varname;
+    Gtk::TreeModelColumn<Glib::ustring> value;
+    EnvVarModelColumns() { add (varname); add (value); }
+};
+
+struct RunProgramDialog::Priv {
+private:
+    Priv ();
+
+public:
+    Gtk::FileChooserButton *fcbutton;
+    Gtk::Button *okbutton;
+    Gtk::TreeView* treeview_environment;
+    Gtk::Button* remove_button;
+    Gtk::Button* add_button;
+    EnvVarModelColumns env_columns;
+    Glib::RefPtr<Gtk::ListStore> model;
+    Gtk::Dialog &dialog;
+    Glib::RefPtr<Gtk::Builder> gtkbuilder;
+
+
+    Priv (Gtk::Dialog &a_dialog,
+        const Glib::RefPtr<Gtk::Builder> &a_gtkbuilder) :
+        fcbutton (0),
+        okbutton (0),
+        treeview_environment (0),
+        remove_button (0),
+        add_button (0),
+        model (Gtk::ListStore::create (env_columns)),
+        dialog (a_dialog),
+        gtkbuilder (a_gtkbuilder)
+    {
+        init ();
+    }
+
+    void init ()
+    {
+        okbutton =
+            ui_utils::get_widget_from_gtkbuilder<Gtk::Button>
+                (gtkbuilder, "executebutton");
+        THROW_IF_FAIL (okbutton);
+        okbutton->set_sensitive (false);
+
+        treeview_environment =
+            ui_utils::get_widget_from_gtkbuilder<Gtk::TreeView>
+                                            (gtkbuilder, "treeview_environment");
+
+        treeview_environment->set_model (model);
+
+        treeview_environment->append_column_editable
+                                        (_("Name"), env_columns.varname);
+
+        treeview_environment->append_column_editable
+                                            (_("Value"), env_columns.value);
+
+        add_button =
+            ui_utils::get_widget_from_gtkbuilder<Gtk::Button>
+                                                    (gtkbuilder, "button_add_var");
+        THROW_IF_FAIL (add_button);
+
+        add_button->signal_clicked().connect(sigc::mem_fun(*this,
+                    &RunProgramDialog::Priv::on_add_new_variable));
+
+        remove_button = ui_utils::get_widget_from_gtkbuilder<Gtk::Button>
+                                                (gtkbuilder, "button_remove_var");
+        THROW_IF_FAIL (remove_button);
+        remove_button->signal_clicked().connect(sigc::mem_fun(*this,
+                    &RunProgramDialog::Priv::on_remove_variable));
+
+        // we need to disable / enable sensitivity of the
+        // "Remove variable" button based on whether a
+        // variable is selected in the treeview.
+        treeview_environment->get_selection ()->signal_changed ().connect
+            (sigc::mem_fun
+                 (*this,
+                  &RunProgramDialog::Priv::on_variable_selection_changed));
+
+        fcbutton =
+            ui_utils::get_widget_from_gtkbuilder<Gtk::FileChooserButton>
+                                                (gtkbuilder, "filechooserbutton");
+        THROW_IF_FAIL (fcbutton);
+        fcbutton->set_show_hidden (true);
+        fcbutton->signal_selection_changed ().connect (sigc::mem_fun
+                (*this, &Priv::on_file_selection_changed));
+
+        // activate the default action (execute) when pressing enter in the
+        // arguments text box
+        ui_utils::get_widget_from_gtkbuilder<Gtk::Entry>
+                        (gtkbuilder, "argumentsentry")->set_activates_default ();
+    }
+
+    void on_add_new_variable ()
+    {
+        THROW_IF_FAIL(model);
+        THROW_IF_FAIL(treeview_environment);
+        Gtk::TreeModel::iterator treeiter = model->append ();
+        Gtk::TreeModel::Path path = model->get_path (treeiter);
+        // activate the first cell of the newly
+        // added row so that the user can start
+        // typing in the name and value of the variable
+        treeview_environment->set_cursor (path,
+                *treeview_environment->get_column (0), true);
+    }
+
+    void on_remove_variable ()
+    {
+        THROW_IF_FAIL(treeview_environment);
+        Gtk::TreeModel::iterator treeiter =
+            treeview_environment->get_selection ()->get_selected ();
+        if (treeiter)
+        {
+            model->erase(treeiter);
+        }
+    }
+
+    void on_variable_selection_changed ()
+    {
+        THROW_IF_FAIL (remove_button);
+        if (treeview_environment->get_selection ()->count_selected_rows ()) {
+            remove_button->set_sensitive();
+        } else {
+            remove_button->set_sensitive(false);
+        }
+    }
+
+    void on_activate_textentry ()
+    {
+        dialog.activate_default ();
+    }
+
+    void on_file_selection_changed ()
+    {
+        if (okbutton && fcbutton) {
+            if (Glib::file_test
+                    (Glib::locale_from_utf8 (fcbutton->get_filename ()),
+                                             Glib::FILE_TEST_IS_EXECUTABLE)) {
+                okbutton->set_sensitive (true);
+            }
+        }
+    }
+};//end struct RunProgramDialog::Priv
+
+RunProgramDialog::RunProgramDialog (const UString &a_root_path) :
+    Dialog (a_root_path, "runprogramdialog.ui", "runprogramdialog")
+{
+    m_priv.reset (new Priv (widget (), gtkbuilder ()));
+    THROW_IF_FAIL (m_priv);
+
+    working_directory (Glib::filename_to_utf8 (Glib::get_current_dir ()));
+}
+
+RunProgramDialog::~RunProgramDialog ()
+{
+    LOG_D ("destroyed", "destructor-domain");
+}
+
+UString
+RunProgramDialog::program_name () const
+{
+    Gtk::FileChooserButton *chooser =
+        ui_utils::get_widget_from_gtkbuilder<Gtk::FileChooserButton>
+                                        (gtkbuilder (), "filechooserbutton");
+    return chooser->get_filename ();
+}
+
+void
+RunProgramDialog::program_name (const UString &a_name)
+{
+    THROW_IF_FAIL (m_priv);
+
+    Gtk::FileChooserButton *chooser =
+        ui_utils::get_widget_from_gtkbuilder<Gtk::FileChooserButton>
+                                    (gtkbuilder (), "filechooserbutton");
+    THROW_IF_FAIL (chooser);
+    chooser->set_filename (a_name);
+}
+
+UString
+RunProgramDialog::arguments () const
+{
+    Gtk::Entry *entry =
+        ui_utils::get_widget_from_gtkbuilder<Gtk::Entry> (gtkbuilder (),
+                                                     "argumentsentry");
+    THROW_IF_FAIL (entry);
+    return entry->get_text ();
+}
+
+void
+RunProgramDialog::arguments (const UString &a_args)
+{
+    Gtk::Entry *entry =
+        ui_utils::get_widget_from_gtkbuilder<Gtk::Entry> (gtkbuilder (),
+                                                     "argumentsentry");
+    THROW_IF_FAIL (entry);
+    entry->set_text (a_args);
+}
+
+UString
+RunProgramDialog::working_directory () const
+{
+    Gtk::FileChooserButton *chooser =
+        ui_utils::get_widget_from_gtkbuilder<Gtk::FileChooserButton>
+                                (gtkbuilder (), "filechooserbutton_workingdir");
+    return chooser->get_filename ();
+}
+
+void
+RunProgramDialog::working_directory (const UString &a_dir)
+{
+    Gtk::FileChooserButton *chooser =
+        ui_utils::get_widget_from_gtkbuilder<Gtk::FileChooserButton>
+            (gtkbuilder (), "filechooserbutton_workingdir");
+    if (a_dir == "" || a_dir == ".") {
+        chooser->set_filename
+                    (Glib::locale_to_utf8 (Glib::get_current_dir ()));
+    } else {
+        chooser->set_filename (a_dir);
+    }
+}
+
+map<UString, UString>
+RunProgramDialog::environment_variables () const
+{
+    THROW_IF_FAIL (m_priv);
+    THROW_IF_FAIL (m_priv->model);
+    map<UString, UString> env_vars;
+    for (Gtk::TreeModel::iterator iter = m_priv->model->children().begin ();
+         iter != m_priv->model->children().end();
+         ++iter) {
+        // for some reason I have to explicitly convert from Glib::ustring to
+        // UString here or it won't compile
+        env_vars[UString((*iter)[m_priv->env_columns.varname])] =
+            UString((*iter)[m_priv->env_columns.value]);
+    }
+    return env_vars;
+}
+
+void
+RunProgramDialog::environment_variables (const map<UString, UString> &vars)
+{
+    THROW_IF_FAIL (m_priv);
+    THROW_IF_FAIL (m_priv->model);
+    // clear out the old data so we can set the new data
+    m_priv->model->clear();
+    for (map<UString, UString>::const_iterator iter = vars.begin();
+         iter != vars.end();
+         ++iter) {
+        Gtk::TreeModel::iterator treeiter = m_priv->model->append();
+        (*treeiter)[m_priv->env_columns.varname] = iter->first;
+        (*treeiter)[m_priv->env_columns.value] = iter->second;
+    }
+}
+
+}//end namespace nemiver
+
diff --git a/src/persp/profperspective/nmv-run-program-dialog.h b/src/persp/profperspective/nmv-run-program-dialog.h
new file mode 100644
index 0000000..a72e001
--- /dev/null
+++ b/src/persp/profperspective/nmv-run-program-dialog.h
@@ -0,0 +1,69 @@
+//Author: Dodji Seketeli
+/*
+ *This file is part of the Nemiver project
+ *
+ *Nemiver is free software; you can redistribute
+ *it and/or modify it under the terms of
+ *the GNU General Public License as published by the
+ *Free Software Foundation; either version 2,
+ *or (at your option) any later version.
+ *
+ *Nemiver is distributed in the hope that it will
+ *be useful, but WITHOUT ANY WARRANTY;
+ *without even the implied warranty of
+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *See the GNU General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with Nemiver;
+ *see the file COPYING.
+ *If not, write to the Free Software Foundation,
+ *Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *See COPYRIGHT file copyright information.
+ */
+#ifndef __NMV_RUN_PROGRAM_DIALOG_H__
+#define __NMV_RUN_PROGRAM_DIALOG_H__
+
+#include <map>
+#include "common/nmv-safe-ptr-utils.h"
+#include "nmv-dialog.h"
+
+NEMIVER_BEGIN_NAMESPACE (nemiver)
+
+namespace common {
+class UString;
+}
+
+using nemiver::common::UString;
+using nemiver::common::SafePtr;
+
+class RunProgramDialog : public Dialog {
+
+    struct Priv;
+    SafePtr<Priv> m_priv;
+
+public:
+
+    RunProgramDialog (const UString &a_resource_root_path);
+
+    virtual ~RunProgramDialog ();
+
+    UString program_name () const;
+    void program_name (const UString &a_name);
+
+    UString arguments () const;
+    void arguments (const UString &a_args);
+
+    UString working_directory () const;
+    void working_directory (const UString &);
+
+    std::map<UString, UString> environment_variables () const;
+    void environment_variables (const std::map<UString, UString> &);
+
+};//end class nemiver
+
+NEMIVER_END_NAMESPACE (nemiver)
+
+#endif //__NMV_RUN_PROGRAM_DIALOG_H__
+
diff --git a/src/persp/profperspective/ui/Makefile.am b/src/persp/profperspective/ui/Makefile.am
index b7347c3..09c4985 100644
--- a/src/persp/profperspective/ui/Makefile.am
+++ b/src/persp/profperspective/ui/Makefile.am
@@ -1,5 +1,6 @@
 PLUGIN_NAME=profperspective
-uifiles = loadreportdialog.ui
+uifiles = loadreportdialog.ui \
+runprogramdialog.ui
 
 uidir = @NEMIVER_PLUGINS_DIR@/$(PLUGIN_NAME)/ui
 ui_DATA = $(uifiles)
diff --git a/src/persp/profperspective/ui/runprogramdialog.ui b/src/persp/profperspective/ui/runprogramdialog.ui
new file mode 100644
index 0000000..22928ed
--- /dev/null
+++ b/src/persp/profperspective/ui/runprogramdialog.ui
@@ -0,0 +1,329 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- interface-requires gtk+ 2.6 -->
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkDialog" id="runprogramdialog">
+    <property name="width_request">300</property>
+    <property name="title" translatable="yes">Choose a Program to Execute</property>
+    <property name="default_width">350</property>
+    <property name="default_height">400</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="border_width">6</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkFrame" id="frame_program">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment2">
+                    <property name="visible">True</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkFileChooserButton" id="filechooserbutton">
+                        <property name="visible">True</property>
+                        <property name="title" translatable="yes">Choose an Executable</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label_program">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Program:</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="frame_arguments">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment1">
+                    <property name="visible">True</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkEntry" id="argumentsentry">
+                        <property name="visible">True</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label_arguments">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Arguments:</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="frame_workingdir">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment3">
+                    <property name="visible">True</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkFileChooserButton" id="filechooserbutton_workingdir">
+                        <property name="visible">True</property>
+                        <property name="action">select-folder</property>
+                        <property name="title" translatable="yes">Choose a Working Directory</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label_workingdir">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Working Directory:</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="frame_environment">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment4">
+                    <property name="visible">True</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkHBox" id="hbox2">
+                        <property name="visible">True</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkScrolledWindow" id="scrolledwindow1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="hscrollbar_policy">automatic</property>
+                            <property name="vscrollbar_policy">automatic</property>
+                            <property name="shadow_type">out</property>
+                            <child>
+                              <object class="GtkTreeView" id="treeview_environment">
+                                <property name="visible">True</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkVButtonBox" id="vbuttonbox1">
+                            <property name="visible">True</property>
+                            <property name="spacing">6</property>
+                            <property name="layout_style">start</property>
+                            <child>
+                              <object class="GtkButton" id="button_add_var">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="can_default">True</property>
+                                <property name="receives_default">False</property>
+                                <child>
+                                  <object class="GtkAlignment" id="alignment6">
+                                    <property name="visible">True</property>
+                                    <property name="xscale">0</property>
+                                    <property name="yscale">0</property>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox3">
+                                        <property name="visible">True</property>
+                                        <property name="spacing">2</property>
+                                        <child>
+                                          <object class="GtkImage" id="image4">
+                                            <property name="visible">True</property>
+                                            <property name="stock">gtk-add</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkLabel" id="label2">
+                                            <property name="visible">True</property>
+                                            <property name="label" translatable="yes">_Add</property>
+                                            <property name="use_underline">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="button_remove_var">
+                                <property name="visible">True</property>
+                                <property name="sensitive">False</property>
+                                <property name="can_focus">True</property>
+                                <property name="can_default">True</property>
+                                <property name="receives_default">False</property>
+                                <child>
+                                  <object class="GtkAlignment" id="alignment7">
+                                    <property name="visible">True</property>
+                                    <property name="xscale">0</property>
+                                    <property name="yscale">0</property>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox4">
+                                        <property name="visible">True</property>
+                                        <property name="spacing">2</property>
+                                        <child>
+                                          <object class="GtkImage" id="image5">
+                                            <property name="visible">True</property>
+                                            <property name="stock">gtk-remove</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkLabel" id="label3">
+                                            <property name="visible">True</property>
+                                            <property name="label" translatable="yes">_Remove</property>
+                                            <property name="use_underline">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label_environment">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Environment Variables:</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button2">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="receives_default">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="executebutton">
+                <property name="label">gtk-execute</property>
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-6">button2</action-widget>
+      <action-widget response="-5">executebutton</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/src/profengine/nmv-i-profiler.h b/src/profengine/nmv-i-profiler.h
index 50d215b..6e44192 100644
--- a/src/profengine/nmv-i-profiler.h
+++ b/src/profengine/nmv-i-profiler.h
@@ -67,10 +67,18 @@ public:
     /// @{
     virtual sigc::signal<void, CallGraphSafePtr>
         report_done_signal () const = 0;
+
+    virtual sigc::signal<void, const UString&> record_done_signal () const = 0;
     /// @}
 
     virtual void report (const UString &a_data_file) = 0;
 
+    virtual void record (const UString &a_program_path,
+                         const std::vector<UString> &a_argv) = 0;
+
+//    virtual void attach_to_pid () = 0;
+
+
 };//end IProfiler
 
 NEMIVER_END_NAMESPACE (nemiver)
diff --git a/src/profengine/nmv-perf-engine.cc b/src/profengine/nmv-perf-engine.cc
index 2022d77..8d79c66 100644
--- a/src/profengine/nmv-perf-engine.cc
+++ b/src/profengine/nmv-perf-engine.cc
@@ -30,12 +30,15 @@
 #include <istream>
 #include <stack>
 #include <sys/wait.h>
+#include <cstdio>
 
 NEMIVER_BEGIN_NAMESPACE (nemiver)
 
 const char *const PERF_REPORT_PARSING_DOMAIN = "perf-report-parsing-domain";
 
 using common::DynModIfaceSafePtr;
+using common::FreeUnref;
+using common::DefaultRef;
 
 struct PerfEngine::Priv {
     int perf_pid;
@@ -43,11 +46,13 @@ struct PerfEngine::Priv {
     int perf_stdout_fd;
     int perf_stderr_fd;
     Glib::RefPtr<Glib::IOChannel> perf_stdout_channel;
+    UString record_filepath;
 
     std::stack<CallGraphNodeSafePtr> call_stack;
     CallGraphSafePtr call_graph;
 
     sigc::signal<void, CallGraphSafePtr> report_done_signal;
+    sigc::signal<void, const UString&> record_done_signal;
 
     Priv () :
         perf_pid (0),
@@ -60,6 +65,30 @@ struct PerfEngine::Priv {
     }
 
     bool
+    on_wait_for_record_to_exit ()
+    {
+        NEMIVER_TRY
+
+        int status = 0;
+        pid_t pid = waitpid (perf_pid, &status, WNOHANG);
+        if (pid == perf_pid && WIFEXITED (status)) {
+            g_spawn_close_pid (perf_pid);
+            perf_pid = 0;
+            master_pty_fd = 0;
+            perf_stdout_fd = 0;
+            perf_stderr_fd = 0;
+
+            record_done_signal.emit (record_filepath);
+
+            return false;
+        }
+
+        NEMIVER_CATCH_NOX
+
+        return true;
+    }
+
+    bool
     on_wait_for_report_to_exit ()
     {
         NEMIVER_TRY
@@ -221,6 +250,36 @@ PerfEngine::~PerfEngine ()
 }
 
 void
+PerfEngine::record (const UString &a_program_path,
+                    const std::vector<UString> &a_argv)
+{
+    SafePtr<char, DefaultRef, FreeUnref> tmp_filepath (tempnam(0, 0));
+    THROW_IF_FAIL (tmp_filepath);
+
+    THROW_IF_FAIL (m_priv);
+    m_priv->record_filepath = tmp_filepath.get ();
+
+    std::vector<UString> argv;
+    argv.push_back ("perf");
+    argv.push_back ("record");
+    argv.push_back ("--output");
+    argv.push_back (m_priv->record_filepath);
+    argv.push_back (a_program_path);
+    argv.insert (argv.end (), a_argv.begin (), a_argv.end ());
+
+    bool is_launched = common::launch_program (argv,
+                                               m_priv->perf_pid,
+                                               m_priv->master_pty_fd,
+                                               m_priv->perf_stdout_fd,
+                                               m_priv->perf_stderr_fd);
+    THROW_IF_FAIL (is_launched);
+
+    Glib::RefPtr<Glib::MainContext> context = Glib::MainContext::get_default ();
+    context->signal_idle ().connect (sigc::mem_fun
+        (m_priv.get (), &PerfEngine::Priv::on_wait_for_record_to_exit));
+}
+
+void
 PerfEngine::report (const UString &a_data_file)
 {
     std::vector<UString> argv;
@@ -261,6 +320,13 @@ PerfEngine::report_done_signal () const
     return m_priv->report_done_signal;
 }
 
+sigc::signal<void, const UString&>
+PerfEngine::record_done_signal () const
+{
+    THROW_IF_FAIL (m_priv);
+    return m_priv->record_done_signal;
+}
+
 //****************************
 //</GDBEngine methods>
 //****************************
diff --git a/src/profengine/nmv-perf-engine.h b/src/profengine/nmv-perf-engine.h
index 7076ab7..69a1eb0 100644
--- a/src/profengine/nmv-perf-engine.h
+++ b/src/profengine/nmv-perf-engine.h
@@ -44,8 +44,12 @@ public:
 
     void report (const UString &a_data_file);
 
-    sigc::signal<void, CallGraphSafePtr> report_done_signal () const;
+    void record (const UString &a_program_path,
+                 const std::vector<UString> &a_argv);
 
+    sigc::signal<void, CallGraphSafePtr> report_done_signal () const;
+    sigc::signal<void> program_exited_signal () const;
+    sigc::signal<void, const UString&> record_done_signal () const;
 }; // end namespace PerfEngine
 
 NEMIVER_END_NAMESPACE (nemiver)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]