* Re: [PATCH 1/8] perf db-export: Add calls parent_id
[not found] ` <20190228130031.23064-2-adrian.hunter@intel.com>
@ 2019-03-01 17:52 ` Arnaldo Carvalho de Melo
0 siblings, 0 replies; 8+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-01 17:52 UTC (permalink / raw)
To: Adrian Hunter; +Cc: Jiri Olsa, Linux Kernel Mailing List
Em Thu, Feb 28, 2019 at 03:00:24PM +0200, Adrian Hunter escreveu:
> The call_path can be used to find the parent symbol for a call but not the
> exact parent call. To do that add parent_id to the call_return export. This
> enables the creation of a call tree from the exported data.
Thanks, applied.
- Arnaldo
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> tools/perf/util/db-export.c | 15 ++++++++++-----
> tools/perf/util/db-export.h | 3 ++-
> .../util/scripting-engines/trace-event-python.c | 8 +++++---
> tools/perf/util/thread-stack.c | 16 ++++++++++++++--
> tools/perf/util/thread-stack.h | 6 ++++--
> 5 files changed, 35 insertions(+), 13 deletions(-)
>
> diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
> index de9b4769d06c..d7315a00c731 100644
> --- a/tools/perf/util/db-export.c
> +++ b/tools/perf/util/db-export.c
> @@ -510,18 +510,23 @@ int db_export__call_path(struct db_export *dbe, struct call_path *cp)
> return 0;
> }
>
> -int db_export__call_return(struct db_export *dbe, struct call_return *cr)
> +int db_export__call_return(struct db_export *dbe, struct call_return *cr,
> + u64 *parent_db_id)
> {
> int err;
>
> - if (cr->db_id)
> - return 0;
> -
> err = db_export__call_path(dbe, cr->cp);
> if (err)
> return err;
>
> - cr->db_id = ++dbe->call_return_last_db_id;
> + if (!cr->db_id)
> + cr->db_id = ++dbe->call_return_last_db_id;
> +
> + if (parent_db_id) {
> + if (!*parent_db_id)
> + *parent_db_id = ++dbe->call_return_last_db_id;
> + cr->parent_db_id = *parent_db_id;
> + }
>
> if (dbe->export_call_return)
> return dbe->export_call_return(dbe, cr);
> diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h
> index 67bc6b8ad2d6..4e2424c89df9 100644
> --- a/tools/perf/util/db-export.h
> +++ b/tools/perf/util/db-export.h
> @@ -104,6 +104,7 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
> int db_export__branch_types(struct db_export *dbe);
>
> int db_export__call_path(struct db_export *dbe, struct call_path *cp);
> -int db_export__call_return(struct db_export *dbe, struct call_return *cr);
> +int db_export__call_return(struct db_export *dbe, struct call_return *cr,
> + u64 *parent_db_id);
>
> #endif
> diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
> index 0e17db41b49b..09604c6508f0 100644
> --- a/tools/perf/util/scripting-engines/trace-event-python.c
> +++ b/tools/perf/util/scripting-engines/trace-event-python.c
> @@ -1173,7 +1173,7 @@ static int python_export_call_return(struct db_export *dbe,
> u64 comm_db_id = cr->comm ? cr->comm->db_id : 0;
> PyObject *t;
>
> - t = tuple_new(11);
> + t = tuple_new(12);
>
> tuple_set_u64(t, 0, cr->db_id);
> tuple_set_u64(t, 1, cr->thread->db_id);
> @@ -1186,6 +1186,7 @@ static int python_export_call_return(struct db_export *dbe,
> tuple_set_u64(t, 8, cr->return_ref);
> tuple_set_u64(t, 9, cr->cp->parent->db_id);
> tuple_set_s32(t, 10, cr->flags);
> + tuple_set_u64(t, 11, cr->parent_db_id);
>
> call_object(tables->call_return_handler, t, "call_return_table");
>
> @@ -1194,11 +1195,12 @@ static int python_export_call_return(struct db_export *dbe,
> return 0;
> }
>
> -static int python_process_call_return(struct call_return *cr, void *data)
> +static int python_process_call_return(struct call_return *cr, u64 *parent_db_id,
> + void *data)
> {
> struct db_export *dbe = data;
>
> - return db_export__call_return(dbe, cr);
> + return db_export__call_return(dbe, cr, parent_db_id);
> }
>
> static void python_process_general_event(struct perf_sample *sample,
> diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
> index a8b45168513c..41942c2aaa18 100644
> --- a/tools/perf/util/thread-stack.c
> +++ b/tools/perf/util/thread-stack.c
> @@ -49,6 +49,7 @@ enum retpoline_state_t {
> * @timestamp: timestamp (if known)
> * @ref: external reference (e.g. db_id of sample)
> * @branch_count: the branch count when the entry was created
> + * @db_id: id used for db-export
> * @cp: call path
> * @no_call: a 'call' was not seen
> * @trace_end: a 'call' but trace ended
> @@ -59,6 +60,7 @@ struct thread_stack_entry {
> u64 timestamp;
> u64 ref;
> u64 branch_count;
> + u64 db_id;
> struct call_path *cp;
> bool no_call;
> bool trace_end;
> @@ -280,12 +282,14 @@ static int thread_stack__call_return(struct thread *thread,
> .comm = ts->comm,
> .db_id = 0,
> };
> + u64 *parent_db_id;
>
> tse = &ts->stack[idx];
> cr.cp = tse->cp;
> cr.call_time = tse->timestamp;
> cr.return_time = timestamp;
> cr.branch_count = ts->branch_count - tse->branch_count;
> + cr.db_id = tse->db_id;
> cr.call_ref = tse->ref;
> cr.return_ref = ref;
> if (tse->no_call)
> @@ -295,7 +299,14 @@ static int thread_stack__call_return(struct thread *thread,
> if (tse->non_call)
> cr.flags |= CALL_RETURN_NON_CALL;
>
> - return crp->process(&cr, crp->data);
> + /*
> + * The parent db_id must be assigned before exporting the child. Note
> + * it is not possible to export the parent first because its information
> + * is not yet complete because its 'return' has not yet been processed.
> + */
> + parent_db_id = idx ? &(tse - 1)->db_id : NULL;
> +
> + return crp->process(&cr, parent_db_id, crp->data);
> }
>
> static int __thread_stack__flush(struct thread *thread, struct thread_stack *ts)
> @@ -484,7 +495,7 @@ void thread_stack__sample(struct thread *thread, int cpu,
> }
>
> struct call_return_processor *
> -call_return_processor__new(int (*process)(struct call_return *cr, void *data),
> +call_return_processor__new(int (*process)(struct call_return *cr, u64 *parent_db_id, void *data),
> void *data)
> {
> struct call_return_processor *crp;
> @@ -537,6 +548,7 @@ static int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr,
> tse->no_call = no_call;
> tse->trace_end = trace_end;
> tse->non_call = false;
> + tse->db_id = 0;
>
> return 0;
> }
> diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h
> index b7c04e19ad41..9c45f947f5a9 100644
> --- a/tools/perf/util/thread-stack.h
> +++ b/tools/perf/util/thread-stack.h
> @@ -55,6 +55,7 @@ enum {
> * @call_ref: external reference to 'call' sample (e.g. db_id)
> * @return_ref: external reference to 'return' sample (e.g. db_id)
> * @db_id: id used for db-export
> + * @parent_db_id: id of parent call used for db-export
> * @flags: Call/Return flags
> */
> struct call_return {
> @@ -67,6 +68,7 @@ struct call_return {
> u64 call_ref;
> u64 return_ref;
> u64 db_id;
> + u64 parent_db_id;
> u32 flags;
> };
>
> @@ -79,7 +81,7 @@ struct call_return {
> */
> struct call_return_processor {
> struct call_path_root *cpr;
> - int (*process)(struct call_return *cr, void *data);
> + int (*process)(struct call_return *cr, u64 *parent_db_id, void *data);
> void *data;
> };
>
> @@ -93,7 +95,7 @@ void thread_stack__free(struct thread *thread);
> size_t thread_stack__depth(struct thread *thread, int cpu);
>
> struct call_return_processor *
> -call_return_processor__new(int (*process)(struct call_return *cr, void *data),
> +call_return_processor__new(int (*process)(struct call_return *cr, u64 *parent_db_id, void *data),
> void *data);
> void call_return_processor__free(struct call_return_processor *crp);
> int thread_stack__process(struct thread *thread, struct comm *comm,
> --
> 2.17.1
--
- Arnaldo
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/8] perf scripts python: export-to-sqlite.py: Export calls parent_id
[not found] ` <20190228130031.23064-3-adrian.hunter@intel.com>
@ 2019-03-01 17:52 ` Arnaldo Carvalho de Melo
0 siblings, 0 replies; 8+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-01 17:52 UTC (permalink / raw)
To: Adrian Hunter; +Cc: Jiri Olsa, Linux Kernel Mailing List
Em Thu, Feb 28, 2019 at 03:00:25PM +0200, Adrian Hunter escreveu:
> Export to the 'calls' table the newly created 'parent_id'.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Thanks, applied.
- Arnaldo
> ---
> tools/perf/scripts/python/export-to-sqlite.py | 12 ++++++++----
> 1 file changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/tools/perf/scripts/python/export-to-sqlite.py b/tools/perf/scripts/python/export-to-sqlite.py
> index ed237f2ed03f..eb63e6c7107f 100644
> --- a/tools/perf/scripts/python/export-to-sqlite.py
> +++ b/tools/perf/scripts/python/export-to-sqlite.py
> @@ -222,7 +222,8 @@ if perf_db_export_calls:
> 'call_id bigint,'
> 'return_id bigint,'
> 'parent_call_path_id bigint,'
> - 'flags integer)')
> + 'flags integer,'
> + 'parent_id bigint)')
>
> # printf was added to sqlite in version 3.8.3
> sqlite_has_printf = False
> @@ -321,7 +322,8 @@ if perf_db_export_calls:
> 'call_id,'
> 'return_id,'
> 'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE flags END AS flags,'
> - 'parent_call_path_id'
> + 'parent_call_path_id,'
> + 'parent_id'
> ' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id')
>
> do_query(query, 'CREATE VIEW samples_view AS '
> @@ -373,7 +375,7 @@ if perf_db_export_calls or perf_db_export_callchains:
> call_path_query.prepare("INSERT INTO call_paths VALUES (?, ?, ?, ?)")
> if perf_db_export_calls:
> call_query = QSqlQuery(db)
> - call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
> + call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
>
> def trace_begin():
> print datetime.datetime.today(), "Writing records..."
> @@ -388,6 +390,7 @@ def trace_begin():
> sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
> if perf_db_export_calls or perf_db_export_callchains:
> call_path_table(0, 0, 0, 0)
> + call_return_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
>
> unhandled_count = 0
>
> @@ -397,6 +400,7 @@ def trace_end():
> print datetime.datetime.today(), "Adding indexes"
> if perf_db_export_calls:
> do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
> + do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)')
>
> if (unhandled_count):
> print datetime.datetime.today(), "Warning: ", unhandled_count, " unhandled events"
> @@ -452,4 +456,4 @@ def call_path_table(*x):
> bind_exec(call_path_query, 4, x)
>
> def call_return_table(*x):
> - bind_exec(call_query, 11, x)
> + bind_exec(call_query, 12, x)
> --
> 2.17.1
--
- Arnaldo
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 4/8] perf scripts python: export-to-postgresql.py: Export calls parent_id
[not found] ` <20190228130031.23064-5-adrian.hunter@intel.com>
@ 2019-03-01 17:54 ` Arnaldo Carvalho de Melo
0 siblings, 0 replies; 8+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-01 17:54 UTC (permalink / raw)
To: Adrian Hunter; +Cc: Jiri Olsa, Linux Kernel Mailing List
Em Thu, Feb 28, 2019 at 03:00:27PM +0200, Adrian Hunter escreveu:
> Export to the 'calls' table the newly created 'parent_id' and create an
> index for it.
Thanks, applied.
- Arnaldo
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> tools/perf/scripts/python/export-to-postgresql.py | 14 +++++++++-----
> 1 file changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py
> index 6358522a69f6..390a351d15ea 100644
> --- a/tools/perf/scripts/python/export-to-postgresql.py
> +++ b/tools/perf/scripts/python/export-to-postgresql.py
> @@ -394,7 +394,8 @@ if perf_db_export_calls:
> 'call_id bigint,'
> 'return_id bigint,'
> 'parent_call_path_id bigint,'
> - 'flags integer)')
> + 'flags integer,'
> + 'parent_id bigint)')
>
> do_query(query, 'CREATE VIEW machines_view AS '
> 'SELECT '
> @@ -479,7 +480,8 @@ if perf_db_export_calls:
> 'call_id,'
> 'return_id,'
> 'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE CAST ( flags AS VARCHAR(6) ) END AS flags,'
> - 'parent_call_path_id'
> + 'parent_call_path_id,'
> + 'calls.parent_id'
> ' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id')
>
> do_query(query, 'CREATE VIEW samples_view AS '
> @@ -575,6 +577,7 @@ def trace_begin():
> sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
> if perf_db_export_calls or perf_db_export_callchains:
> call_path_table(0, 0, 0, 0)
> + call_return_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
>
> unhandled_count = 0
>
> @@ -657,6 +660,7 @@ def trace_end():
> 'ADD CONSTRAINT returnfk FOREIGN KEY (return_id) REFERENCES samples (id),'
> 'ADD CONSTRAINT parent_call_pathfk FOREIGN KEY (parent_call_path_id) REFERENCES call_paths (id)')
> do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
> + do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)')
>
> if (unhandled_count):
> print datetime.datetime.today(), "Warning: ", unhandled_count, " unhandled events"
> @@ -728,7 +732,7 @@ def call_path_table(cp_id, parent_id, symbol_id, ip, *x):
> value = struct.pack(fmt, 4, 8, cp_id, 8, parent_id, 8, symbol_id, 8, ip)
> call_path_file.write(value)
>
> -def call_return_table(cr_id, thread_id, comm_id, call_path_id, call_time, return_time, branch_count, call_id, return_id, parent_call_path_id, flags, *x):
> - fmt = "!hiqiqiqiqiqiqiqiqiqiqii"
> - value = struct.pack(fmt, 11, 8, cr_id, 8, thread_id, 8, comm_id, 8, call_path_id, 8, call_time, 8, return_time, 8, branch_count, 8, call_id, 8, return_id, 8, parent_call_path_id, 4, flags)
> +def call_return_table(cr_id, thread_id, comm_id, call_path_id, call_time, return_time, branch_count, call_id, return_id, parent_call_path_id, flags, parent_id, *x):
> + fmt = "!hiqiqiqiqiqiqiqiqiqiqiiiq"
> + value = struct.pack(fmt, 12, 8, cr_id, 8, thread_id, 8, comm_id, 8, call_path_id, 8, call_time, 8, return_time, 8, branch_count, 8, call_id, 8, return_id, 8, parent_call_path_id, 4, flags, 8, parent_id)
> call_file.write(value)
> --
> 2.17.1
--
- Arnaldo
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/8] perf scripts python: export-to-postgresql.py: Fix invalid input syntax for integer error
[not found] ` <20190228130031.23064-4-adrian.hunter@intel.com>
@ 2019-03-01 17:54 ` Arnaldo Carvalho de Melo
0 siblings, 0 replies; 8+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-01 17:54 UTC (permalink / raw)
To: Adrian Hunter; +Cc: Jiri Olsa, Linux Kernel Mailing List
Em Thu, Feb 28, 2019 at 03:00:26PM +0200, Adrian Hunter escreveu:
> Fix SQL query error "invalid input syntax for integer":
>
> Traceback (most recent call last):
> File "tools/perf/scripts/python/export-to-postgresql.py", line 465, in <module>
> do_query(query, 'CREATE VIEW calls_view AS '
> File "tools/perf/scripts/python/export-to-postgresql.py", line 274, in do_query
> raise Exception("Query failed: " + q.lastError().text())
> Exception: Query failed: ERROR: invalid input syntax for integer: ""
> LINE 1: ...ch_count,call_id,return_id,CASE WHEN flags=0 THEN '' WHEN fl...
> ^
> (22P02) QPSQL: Unable to create query
> Error running python script tools/perf/scripts/python/export-to-postgresql.py
Thanks, applied.
- Arnaldo
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> Fixes: f08046cb3082 ("perf thread-stack: Represent jmps to the start of a different symbol")
> ---
> tools/perf/scripts/python/export-to-postgresql.py | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py
> index 30130213da7e..6358522a69f6 100644
> --- a/tools/perf/scripts/python/export-to-postgresql.py
> +++ b/tools/perf/scripts/python/export-to-postgresql.py
> @@ -478,7 +478,7 @@ if perf_db_export_calls:
> 'branch_count,'
> 'call_id,'
> 'return_id,'
> - 'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE flags END AS flags,'
> + 'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE CAST ( flags AS VARCHAR(6) ) END AS flags,'
> 'parent_call_path_id'
> ' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id')
>
> --
> 2.17.1
--
- Arnaldo
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 5/8] perf scripts python: exported-sql-viewer.py: Factor out TreeWindowBase
[not found] ` <20190228130031.23064-6-adrian.hunter@intel.com>
@ 2019-03-01 17:55 ` Arnaldo Carvalho de Melo
0 siblings, 0 replies; 8+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-01 17:55 UTC (permalink / raw)
To: Adrian Hunter; +Cc: Jiri Olsa, Linux Kernel Mailing List
Em Thu, Feb 28, 2019 at 03:00:28PM +0200, Adrian Hunter escreveu:
> Factor out a base class TreeWindowBase from CallGraphWindow, so that
> TreeWindowBase can be reused.
Thanks, applied.
- Arnaldo
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> .../scripts/python/exported-sql-viewer.py | 50 ++++++++++++-------
> 1 file changed, 31 insertions(+), 19 deletions(-)
>
> diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
> index 09ce73b07d35..df854f0a69f0 100755
> --- a/tools/perf/scripts/python/exported-sql-viewer.py
> +++ b/tools/perf/scripts/python/exported-sql-viewer.py
> @@ -693,28 +693,16 @@ class VBox():
> def Widget(self):
> return self.vbox
>
> -# Context-sensitive call graph window
> -
> -class CallGraphWindow(QMdiSubWindow):
> -
> - def __init__(self, glb, parent=None):
> - super(CallGraphWindow, self).__init__(parent)
> +# Tree window base
>
> - self.model = LookupCreateModel("Context-Sensitive Call Graph", lambda x=glb: CallGraphModel(x))
> +class TreeWindowBase(QMdiSubWindow):
>
> - self.view = QTreeView()
> - self.view.setModel(self.model)
> -
> - for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)):
> - self.view.setColumnWidth(c, w)
> -
> - self.find_bar = FindBar(self, self)
> -
> - self.vbox = VBox(self.view, self.find_bar.Widget())
> -
> - self.setWidget(self.vbox.Widget())
> + def __init__(self, parent=None):
> + super(TreeWindowBase, self).__init__(parent)
>
> - AddSubWindow(glb.mainwindow.mdi_area, self, "Context-Sensitive Call Graph")
> + self.model = None
> + self.view = None
> + self.find_bar = None
>
> def DisplayFound(self, ids):
> if not len(ids):
> @@ -747,6 +735,30 @@ class CallGraphWindow(QMdiSubWindow):
> if not found:
> self.find_bar.NotFound()
>
> +
> +# Context-sensitive call graph window
> +
> +class CallGraphWindow(TreeWindowBase):
> +
> + def __init__(self, glb, parent=None):
> + super(CallGraphWindow, self).__init__(parent)
> +
> + self.model = LookupCreateModel("Context-Sensitive Call Graph", lambda x=glb: CallGraphModel(x))
> +
> + self.view = QTreeView()
> + self.view.setModel(self.model)
> +
> + for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)):
> + self.view.setColumnWidth(c, w)
> +
> + self.find_bar = FindBar(self, self)
> +
> + self.vbox = VBox(self.view, self.find_bar.Widget())
> +
> + self.setWidget(self.vbox.Widget())
> +
> + AddSubWindow(glb.mainwindow.mdi_area, self, "Context-Sensitive Call Graph")
> +
> # Child data item finder
>
> class ChildDataItemFinder():
> --
> 2.17.1
--
- Arnaldo
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 6/8] perf scripts python: exported-sql-viewer.py: Improve TreeModel abstraction
[not found] ` <20190228130031.23064-7-adrian.hunter@intel.com>
@ 2019-03-01 17:55 ` Arnaldo Carvalho de Melo
0 siblings, 0 replies; 8+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-01 17:55 UTC (permalink / raw)
To: Adrian Hunter; +Cc: Jiri Olsa, Linux Kernel Mailing List
Em Thu, Feb 28, 2019 at 03:00:29PM +0200, Adrian Hunter escreveu:
> Instead of passing the tree root, get it from a method that can be
> implemented in any derived class.
Thanks, applied.
- Arnaldo
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> .../perf/scripts/python/exported-sql-viewer.py | 17 +++++++++++------
> 1 file changed, 11 insertions(+), 6 deletions(-)
>
> diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
> index df854f0a69f0..b2a22525549d 100755
> --- a/tools/perf/scripts/python/exported-sql-viewer.py
> +++ b/tools/perf/scripts/python/exported-sql-viewer.py
> @@ -167,9 +167,10 @@ class Thread(QThread):
>
> class TreeModel(QAbstractItemModel):
>
> - def __init__(self, root, parent=None):
> + def __init__(self, glb, parent=None):
> super(TreeModel, self).__init__(parent)
> - self.root = root
> + self.glb = glb
> + self.root = self.GetRoot()
> self.last_row_read = 0
>
> def Item(self, parent):
> @@ -562,8 +563,10 @@ class CallGraphRootItem(CallGraphLevelItemBase):
> class CallGraphModel(TreeModel):
>
> def __init__(self, glb, parent=None):
> - super(CallGraphModel, self).__init__(CallGraphRootItem(glb), parent)
> - self.glb = glb
> + super(CallGraphModel, self).__init__(glb, parent)
> +
> + def GetRoot(self):
> + return CallGraphRootItem(self.glb)
>
> def columnCount(self, parent=None):
> return 7
> @@ -1339,8 +1342,7 @@ class BranchModel(TreeModel):
> progress = Signal(object)
>
> def __init__(self, glb, event_id, where_clause, parent=None):
> - super(BranchModel, self).__init__(BranchRootItem(), parent)
> - self.glb = glb
> + super(BranchModel, self).__init__(glb, parent)
> self.event_id = event_id
> self.more = True
> self.populated = 0
> @@ -1364,6 +1366,9 @@ class BranchModel(TreeModel):
> self.fetcher.done.connect(self.Update)
> self.fetcher.Fetch(glb_chunk_sz)
>
> + def GetRoot(self):
> + return BranchRootItem()
> +
> def columnCount(self, parent=None):
> return 8
>
> --
> 2.17.1
--
- Arnaldo
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 7/8] perf scripts python: exported-sql-viewer.py: Factor out CallGraphModelBase
[not found] ` <20190228130031.23064-8-adrian.hunter@intel.com>
@ 2019-03-01 17:56 ` Arnaldo Carvalho de Melo
0 siblings, 0 replies; 8+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-01 17:56 UTC (permalink / raw)
To: Adrian Hunter; +Cc: Jiri Olsa, Linux Kernel Mailing List
Em Thu, Feb 28, 2019 at 03:00:30PM +0200, Adrian Hunter escreveu:
> Factor out a base class CallGraphModelBase from CallGraphModel, so that
> CallGraphModelBase can be reused.
Thanks, applied.
- Arnaldo
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> .../scripts/python/exported-sql-viewer.py | 100 ++++++++++--------
> 1 file changed, 55 insertions(+), 45 deletions(-)
>
> diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
> index b2a22525549d..c4a2134d85f5 100755
> --- a/tools/perf/scripts/python/exported-sql-viewer.py
> +++ b/tools/perf/scripts/python/exported-sql-viewer.py
> @@ -558,26 +558,12 @@ class CallGraphRootItem(CallGraphLevelItemBase):
> self.child_items.append(child_item)
> self.child_count += 1
>
> -# Context-sensitive call graph data model
> +# Context-sensitive call graph data model base
>
> -class CallGraphModel(TreeModel):
> +class CallGraphModelBase(TreeModel):
>
> def __init__(self, glb, parent=None):
> - super(CallGraphModel, self).__init__(glb, parent)
> -
> - def GetRoot(self):
> - return CallGraphRootItem(self.glb)
> -
> - def columnCount(self, parent=None):
> - return 7
> -
> - def columnHeader(self, column):
> - headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "]
> - return headers[column]
> -
> - def columnAlignment(self, column):
> - alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ]
> - return alignment[column]
> + super(CallGraphModelBase, self).__init__(glb, parent)
>
> def FindSelect(self, value, pattern, query):
> if pattern:
> @@ -597,34 +583,7 @@ class CallGraphModel(TreeModel):
> match = " GLOB '" + str(value) + "'"
> else:
> match = " = '" + str(value) + "'"
> - QueryExec(query, "SELECT call_path_id, comm_id, thread_id"
> - " FROM calls"
> - " INNER JOIN call_paths ON calls.call_path_id = call_paths.id"
> - " INNER JOIN symbols ON call_paths.symbol_id = symbols.id"
> - " WHERE symbols.name" + match +
> - " GROUP BY comm_id, thread_id, call_path_id"
> - " ORDER BY comm_id, thread_id, call_path_id")
> -
> - def FindPath(self, query):
> - # Turn the query result into a list of ids that the tree view can walk
> - # to open the tree at the right place.
> - ids = []
> - parent_id = query.value(0)
> - while parent_id:
> - ids.insert(0, parent_id)
> - q2 = QSqlQuery(self.glb.db)
> - QueryExec(q2, "SELECT parent_id"
> - " FROM call_paths"
> - " WHERE id = " + str(parent_id))
> - if not q2.next():
> - break
> - parent_id = q2.value(0)
> - # The call path root is not used
> - if ids[0] == 1:
> - del ids[0]
> - ids.insert(0, query.value(2))
> - ids.insert(0, query.value(1))
> - return ids
> + self.DoFindSelect(query, match)
>
> def Found(self, query, found):
> if found:
> @@ -678,6 +637,57 @@ class CallGraphModel(TreeModel):
> def FindDone(self, thread, callback, ids):
> callback(ids)
>
> +# Context-sensitive call graph data model
> +
> +class CallGraphModel(CallGraphModelBase):
> +
> + def __init__(self, glb, parent=None):
> + super(CallGraphModel, self).__init__(glb, parent)
> +
> + def GetRoot(self):
> + return CallGraphRootItem(self.glb)
> +
> + def columnCount(self, parent=None):
> + return 7
> +
> + def columnHeader(self, column):
> + headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "]
> + return headers[column]
> +
> + def columnAlignment(self, column):
> + alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ]
> + return alignment[column]
> +
> + def DoFindSelect(self, query, match):
> + QueryExec(query, "SELECT call_path_id, comm_id, thread_id"
> + " FROM calls"
> + " INNER JOIN call_paths ON calls.call_path_id = call_paths.id"
> + " INNER JOIN symbols ON call_paths.symbol_id = symbols.id"
> + " WHERE symbols.name" + match +
> + " GROUP BY comm_id, thread_id, call_path_id"
> + " ORDER BY comm_id, thread_id, call_path_id")
> +
> + def FindPath(self, query):
> + # Turn the query result into a list of ids that the tree view can walk
> + # to open the tree at the right place.
> + ids = []
> + parent_id = query.value(0)
> + while parent_id:
> + ids.insert(0, parent_id)
> + q2 = QSqlQuery(self.glb.db)
> + QueryExec(q2, "SELECT parent_id"
> + " FROM call_paths"
> + " WHERE id = " + str(parent_id))
> + if not q2.next():
> + break
> + parent_id = q2.value(0)
> + # The call path root is not used
> + if ids[0] == 1:
> + del ids[0]
> + ids.insert(0, query.value(2))
> + ids.insert(0, query.value(1))
> + return ids
> +
> # Vertical widget layout
>
> class VBox():
> --
> 2.17.1
--
- Arnaldo
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 8/8] perf scripts python: exported-sql-viewer.py: Add call tree
[not found] ` <20190228130031.23064-9-adrian.hunter@intel.com>
@ 2019-03-01 18:20 ` Arnaldo Carvalho de Melo
0 siblings, 0 replies; 8+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-01 18:20 UTC (permalink / raw)
To: Adrian Hunter; +Cc: Jiri Olsa, Linux Kernel Mailing List
Em Thu, Feb 28, 2019 at 03:00:31PM +0200, Adrian Hunter escreveu:
> Add a new report to display a call tree. The Call Tree report is very
> similar to the Context-Sensitive Call Graph, but the data is not
> aggregated. Also the 'Count' column, which would be always 1, is replaced
> by the 'Call Time'.
Thanks, applied and added committer testing notes:
Committer testing:
$ cat simple-retpoline.c
/*
https://lkml.kernel.org/r/20190109091835.5570-6-adrian.hunter@intel.com
$ gcc -ggdb3 -Wall -Wextra -O2 -o simple-retpoline simple-retpoline.c
$ objdump -d simple-retpoline
*/
__attribute__((noinline)) int bar(void)
{
return -1;
}
int foo(void)
{
return bar() + 1;
}
__attribute__((indirect_branch("thunk"))) int main()
{
int (*volatile fn)(void) = foo;
fn();
return fn();
}
$
$ perf record -o simple-retpoline.perf.data -e intel_pt/cyc/u ./simple-retpoline
$ perf script -i simple-retpoline.perf.data --itrace=be -s ~acme/libexec/perf-core/scripts/python/export-to-sqlite.py simple-retpoline.db branches calls
$ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py simple-retpoline.db
And in the GUI select:
"Reports"
"Call Tree"
Call Path | Object | Call Time (ns) | Time (ns) | Time (%) | Branch Count | Brach Count (%) |
> simple-retpolin
> PID:TID
> _start ld-2.28.so 2193855505777 156267 100.0 10602 100.0
unknown unknown 2193855506010 2276 1.5 1 0.0
> _dl_start ld-2.28.so 2193855508286 137047 87.7 10088 95.2
> _dl_init ld-2.28.so 2193855645444 9142 5.9 326 3.1
> _start simple-retpoline 2193855654587 7457 4.8 182 1.7
> __libc_start_main <SNIP>
<SNIP>
> main simple-retpoline 2193855657493 32 0.5 12 6.7
> foo simple-retpoline 2193855657493 14 43.8 5 41.7
<SNIP>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> .../scripts/python/exported-sql-viewer.py | 195 +++++++++++++++++-
> 1 file changed, 186 insertions(+), 9 deletions(-)
>
> diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
> index c4a2134d85f5..afec9479ca7f 100755
> --- a/tools/perf/scripts/python/exported-sql-viewer.py
> +++ b/tools/perf/scripts/python/exported-sql-viewer.py
> @@ -688,6 +688,150 @@ class CallGraphModel(CallGraphModelBase):
> ids.insert(0, query.value(1))
> return ids
>
> +# Call tree data model level 2+ item base
> +
> +class CallTreeLevelTwoPlusItemBase(CallGraphLevelItemBase):
> +
> + def __init__(self, glb, row, comm_id, thread_id, calls_id, time, branch_count, parent_item):
> + super(CallTreeLevelTwoPlusItemBase, self).__init__(glb, row, parent_item)
> + self.comm_id = comm_id
> + self.thread_id = thread_id
> + self.calls_id = calls_id
> + self.branch_count = branch_count
> + self.time = time
> +
> + def Select(self):
> + self.query_done = True;
> + if self.calls_id == 0:
> + comm_thread = " AND comm_id = " + str(self.comm_id) + " AND thread_id = " + str(self.thread_id)
> + else:
> + comm_thread = ""
> + query = QSqlQuery(self.glb.db)
> + QueryExec(query, "SELECT calls.id, name, short_name, call_time, return_time - call_time, branch_count"
> + " FROM calls"
> + " INNER JOIN call_paths ON calls.call_path_id = call_paths.id"
> + " INNER JOIN symbols ON call_paths.symbol_id = symbols.id"
> + " INNER JOIN dsos ON symbols.dso_id = dsos.id"
> + " WHERE calls.parent_id = " + str(self.calls_id) + comm_thread +
> + " ORDER BY call_time, calls.id")
> + while query.next():
> + child_item = CallTreeLevelThreeItem(self.glb, self.child_count, self.comm_id, self.thread_id, query.value(0), query.value(1), query.value(2), query.value(3), int(query.value(4)), int(query.value(5)), self)
> + self.child_items.append(child_item)
> + self.child_count += 1
> +
> +# Call tree data model level three item
> +
> +class CallTreeLevelThreeItem(CallTreeLevelTwoPlusItemBase):
> +
> + def __init__(self, glb, row, comm_id, thread_id, calls_id, name, dso, count, time, branch_count, parent_item):
> + super(CallTreeLevelThreeItem, self).__init__(glb, row, comm_id, thread_id, calls_id, time, branch_count, parent_item)
> + dso = dsoname(dso)
> + self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ]
> + self.dbid = calls_id
> +
> +# Call tree data model level two item
> +
> +class CallTreeLevelTwoItem(CallTreeLevelTwoPlusItemBase):
> +
> + def __init__(self, glb, row, comm_id, thread_id, pid, tid, parent_item):
> + super(CallTreeLevelTwoItem, self).__init__(glb, row, comm_id, thread_id, 0, 0, 0, parent_item)
> + self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""]
> + self.dbid = thread_id
> +
> + def Select(self):
> + super(CallTreeLevelTwoItem, self).Select()
> + for child_item in self.child_items:
> + self.time += child_item.time
> + self.branch_count += child_item.branch_count
> + for child_item in self.child_items:
> + child_item.data[4] = PercentToOneDP(child_item.time, self.time)
> + child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count)
> +
> +# Call tree data model level one item
> +
> +class CallTreeLevelOneItem(CallGraphLevelItemBase):
> +
> + def __init__(self, glb, row, comm_id, comm, parent_item):
> + super(CallTreeLevelOneItem, self).__init__(glb, row, parent_item)
> + self.data = [comm, "", "", "", "", "", ""]
> + self.dbid = comm_id
> +
> + def Select(self):
> + self.query_done = True;
> + query = QSqlQuery(self.glb.db)
> + QueryExec(query, "SELECT thread_id, pid, tid"
> + " FROM comm_threads"
> + " INNER JOIN threads ON thread_id = threads.id"
> + " WHERE comm_id = " + str(self.dbid))
> + while query.next():
> + child_item = CallTreeLevelTwoItem(self.glb, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self)
> + self.child_items.append(child_item)
> + self.child_count += 1
> +
> +# Call tree data model root item
> +
> +class CallTreeRootItem(CallGraphLevelItemBase):
> +
> + def __init__(self, glb):
> + super(CallTreeRootItem, self).__init__(glb, 0, None)
> + self.dbid = 0
> + self.query_done = True;
> + query = QSqlQuery(glb.db)
> + QueryExec(query, "SELECT id, comm FROM comms")
> + while query.next():
> + if not query.value(0):
> + continue
> + child_item = CallTreeLevelOneItem(glb, self.child_count, query.value(0), query.value(1), self)
> + self.child_items.append(child_item)
> + self.child_count += 1
> +
> +# Call Tree data model
> +
> +class CallTreeModel(CallGraphModelBase):
> +
> + def __init__(self, glb, parent=None):
> + super(CallTreeModel, self).__init__(glb, parent)
> +
> + def GetRoot(self):
> + return CallTreeRootItem(self.glb)
> +
> + def columnCount(self, parent=None):
> + return 7
> +
> + def columnHeader(self, column):
> + headers = ["Call Path", "Object", "Call Time", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "]
> + return headers[column]
> +
> + def columnAlignment(self, column):
> + alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ]
> + return alignment[column]
> +
> + def DoFindSelect(self, query, match):
> + QueryExec(query, "SELECT calls.id, comm_id, thread_id"
> + " FROM calls"
> + " INNER JOIN call_paths ON calls.call_path_id = call_paths.id"
> + " INNER JOIN symbols ON call_paths.symbol_id = symbols.id"
> + " WHERE symbols.name" + match +
> + " ORDER BY comm_id, thread_id, call_time, calls.id")
> +
> + def FindPath(self, query):
> + # Turn the query result into a list of ids that the tree view can walk
> + # to open the tree at the right place.
> + ids = []
> + parent_id = query.value(0)
> + while parent_id:
> + ids.insert(0, parent_id)
> + q2 = QSqlQuery(self.glb.db)
> + QueryExec(q2, "SELECT parent_id"
> + " FROM calls"
> + " WHERE id = " + str(parent_id))
> + if not q2.next():
> + break
> + parent_id = q2.value(0)
> + ids.insert(0, query.value(2))
> + ids.insert(0, query.value(1))
> + return ids
> +
> # Vertical widget layout
>
> class VBox():
> @@ -772,6 +916,29 @@ class CallGraphWindow(TreeWindowBase):
>
> AddSubWindow(glb.mainwindow.mdi_area, self, "Context-Sensitive Call Graph")
>
> +# Call tree window
> +
> +class CallTreeWindow(TreeWindowBase):
> +
> + def __init__(self, glb, parent=None):
> + super(CallTreeWindow, self).__init__(parent)
> +
> + self.model = LookupCreateModel("Call Tree", lambda x=glb: CallTreeModel(x))
> +
> + self.view = QTreeView()
> + self.view.setModel(self.model)
> +
> + for c, w in ((0, 230), (1, 100), (2, 100), (3, 70), (4, 70), (5, 100)):
> + self.view.setColumnWidth(c, w)
> +
> + self.find_bar = FindBar(self, self)
> +
> + self.vbox = VBox(self.view, self.find_bar.Widget())
> +
> + self.setWidget(self.vbox.Widget())
> +
> + AddSubWindow(glb.mainwindow.mdi_area, self, "Call Tree")
> +
> # Child data item finder
>
> class ChildDataItemFinder():
> @@ -1890,10 +2057,10 @@ def GetEventList(db):
>
> # Is a table selectable
>
> -def IsSelectable(db, table):
> +def IsSelectable(db, table, sql = ""):
> query = QSqlQuery(db)
> try:
> - QueryExec(query, "SELECT * FROM " + table + " LIMIT 1")
> + QueryExec(query, "SELECT * FROM " + table + " " + sql + " LIMIT 1")
> except:
> return False
> return True
> @@ -2302,9 +2469,10 @@ p.c2 {
> </style>
> <p class=c1><a href=#reports>1. Reports</a></p>
> <p class=c2><a href=#callgraph>1.1 Context-Sensitive Call Graph</a></p>
> -<p class=c2><a href=#allbranches>1.2 All branches</a></p>
> -<p class=c2><a href=#selectedbranches>1.3 Selected branches</a></p>
> -<p class=c2><a href=#topcallsbyelapsedtime>1.4 Top calls by elapsed time</a></p>
> +<p class=c2><a href=#calltree>1.2 Call Tree</a></p>
> +<p class=c2><a href=#allbranches>1.3 All branches</a></p>
> +<p class=c2><a href=#selectedbranches>1.4 Selected branches</a></p>
> +<p class=c2><a href=#topcallsbyelapsedtime>1.5 Top calls by elapsed time</a></p>
> <p class=c1><a href=#tables>2. Tables</a></p>
> <h1 id=reports>1. Reports</h1>
> <h2 id=callgraph>1.1 Context-Sensitive Call Graph</h2>
> @@ -2340,7 +2508,10 @@ v- ls
> <h3>Find</h3>
> Ctrl-F displays a Find bar which finds function names by either an exact match or a pattern match.
> The pattern matching symbols are ? for any character and * for zero or more characters.
> -<h2 id=allbranches>1.2 All branches</h2>
> +<h2 id=calltree>1.2 Call Tree</h2>
> +The Call Tree report is very similar to the Context-Sensitive Call Graph, but the data is not aggregated.
> +Also the 'Count' column, which would be always 1, is replaced by the 'Call Time'.
> +<h2 id=allbranches>1.3 All branches</h2>
> The All branches report displays all branches in chronological order.
> Not all data is fetched immediately. More records can be fetched using the Fetch bar provided.
> <h3>Disassembly</h3>
> @@ -2366,10 +2537,10 @@ sudo ldconfig
> Ctrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match.
> Refer to Python documentation for the regular expression syntax.
> All columns are searched, but only currently fetched rows are searched.
> -<h2 id=selectedbranches>1.3 Selected branches</h2>
> +<h2 id=selectedbranches>1.4 Selected branches</h2>
> This is the same as the <a href=#allbranches>All branches</a> report but with the data reduced
> by various selection criteria. A dialog box displays available criteria which are AND'ed together.
> -<h3>1.3.1 Time ranges</h3>
> +<h3>1.4.1 Time ranges</h3>
> The time ranges hint text shows the total time range. Relative time ranges can also be entered in
> ms, us or ns. Also, negative values are relative to the end of trace. Examples:
> <pre>
> @@ -2380,7 +2551,7 @@ ms, us or ns. Also, negative values are relative to the end of trace. Examples:
> -10ms- The last 10ms
> </pre>
> N.B. Due to the granularity of timestamps, there could be no branches in any given time range.
> -<h2 id=topcallsbyelapsedtime>1.4 Top calls by elapsed time</h2>
> +<h2 id=topcallsbyelapsedtime>1.5 Top calls by elapsed time</h2>
> The Top calls by elapsed time report displays calls in descending order of time elapsed between when the function was called and when it returned.
> The data is reduced by various selection criteria. A dialog box displays available criteria which are AND'ed together.
> If not all data is fetched, a Fetch bar is provided. Ctrl-F displays a Find bar.
> @@ -2516,6 +2687,9 @@ class MainWindow(QMainWindow):
> if IsSelectable(glb.db, "calls"):
> reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self))
>
> + if IsSelectable(glb.db, "calls", "WHERE parent_id >= 0"):
> + reports_menu.addAction(CreateAction("Call &Tree", "Create a new window containing a call tree", self.NewCallTree, self))
> +
> self.EventMenu(GetEventList(glb.db), reports_menu)
>
> if IsSelectable(glb.db, "calls"):
> @@ -2576,6 +2750,9 @@ class MainWindow(QMainWindow):
> def NewCallGraph(self):
> CallGraphWindow(self.glb, self)
>
> + def NewCallTree(self):
> + CallTreeWindow(self.glb, self)
> +
> def NewTopCalls(self):
> dialog = TopCallsDialog(self.glb, self)
> ret = dialog.exec_()
> --
> 2.17.1
--
- Arnaldo
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2019-03-01 18:20 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <20190228130031.23064-1-adrian.hunter@intel.com>
[not found] ` <20190228130031.23064-2-adrian.hunter@intel.com>
2019-03-01 17:52 ` [PATCH 1/8] perf db-export: Add calls parent_id Arnaldo Carvalho de Melo
[not found] ` <20190228130031.23064-3-adrian.hunter@intel.com>
2019-03-01 17:52 ` [PATCH 2/8] perf scripts python: export-to-sqlite.py: Export " Arnaldo Carvalho de Melo
[not found] ` <20190228130031.23064-5-adrian.hunter@intel.com>
2019-03-01 17:54 ` [PATCH 4/8] perf scripts python: export-to-postgresql.py: " Arnaldo Carvalho de Melo
[not found] ` <20190228130031.23064-4-adrian.hunter@intel.com>
2019-03-01 17:54 ` [PATCH 3/8] perf scripts python: export-to-postgresql.py: Fix invalid input syntax for integer error Arnaldo Carvalho de Melo
[not found] ` <20190228130031.23064-6-adrian.hunter@intel.com>
2019-03-01 17:55 ` [PATCH 5/8] perf scripts python: exported-sql-viewer.py: Factor out TreeWindowBase Arnaldo Carvalho de Melo
[not found] ` <20190228130031.23064-7-adrian.hunter@intel.com>
2019-03-01 17:55 ` [PATCH 6/8] perf scripts python: exported-sql-viewer.py: Improve TreeModel abstraction Arnaldo Carvalho de Melo
[not found] ` <20190228130031.23064-8-adrian.hunter@intel.com>
2019-03-01 17:56 ` [PATCH 7/8] perf scripts python: exported-sql-viewer.py: Factor out CallGraphModelBase Arnaldo Carvalho de Melo
[not found] ` <20190228130031.23064-9-adrian.hunter@intel.com>
2019-03-01 18:20 ` [PATCH 8/8] perf scripts python: exported-sql-viewer.py: Add call tree Arnaldo Carvalho de Melo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).