diff options
| author | Adrian Hunter <adrian.hunter@intel.com> | 2014-10-23 06:45:15 -0400 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2014-10-29 08:32:49 -0400 |
| commit | 2987e32f75dcb40bce0f3ab1d5d48cc1c580fd8b (patch) | |
| tree | 51edb002288592d72fbda93f45f0fccb34ab616e | |
| parent | df919b400ad3f9e6aac392ce421d710207abf9be (diff) | |
perf script: Add Python script to export to postgresql
Add a Python script to export to a postgresql database.
The script requires the Python pyside module and the Qt PostgreSQL
driver. The packages needed are probably named "python-pyside" and
"libqt4-sql-psql"
The caller of the script must be able to create postgresql databases.
The script takes the database name as a parameter. The database and
database tables are created. Data is written to flat files which are
then imported using SQL COPY FROM.
Example:
$ perf record ls
...
$ perf script report export-to-postgresql lsdb
2014-02-14 10:55:38.631431 Creating database...
2014-02-14 10:55:39.291958 Writing to intermediate files...
2014-02-14 10:55:39.350280 Copying to database...
2014-02-14 10:55:39.358536 Removing intermediate files...
2014-02-14 10:55:39.358665 Adding primary keys
2014-02-14 10:55:39.658697 Adding foreign keys
2014-02-14 10:55:39.667412 Done
$ psql lsdb
lsdb-# \d
List of relations
Schema | Name | Type | Owner
--------+-----------------+-------+-------
public | comm_threads | table | acme
public | comms | table | acme
public | dsos | table | acme
public | machines | table | acme
public | samples | table | acme
public | samples_view | view | acme
public | selected_events | table | acme
public | symbols | table | acme
public | threads | table | acme
(9 rows)
lsdb-# \d samples
Table "public.samples"
Column | Type | Modifiers
---------------+---------+-----------
id | bigint | not null
evsel_id | bigint |
machine_id | bigint |
thread_id | bigint |
comm_id | bigint |
dso_id | bigint |
symbol_id | bigint |
sym_offset | bigint |
ip | bigint |
time | bigint |
cpu | integer |
to_dso_id | bigint |
to_symbol_id | bigint |
to_sym_offset | bigint |
to_ip | bigint |
period | bigint |
weight | bigint |
transaction | bigint |
data_src | bigint |
Indexes:
"samples_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"commfk" FOREIGN KEY (comm_id) REFERENCES comms(id)
"dsofk" FOREIGN KEY (dso_id) REFERENCES dsos(id)
"evselfk" FOREIGN KEY (evsel_id) REFERENCES selected_events(id)
"machinefk" FOREIGN KEY (machine_id) REFERENCES machines(id)
"symbolfk" FOREIGN KEY (symbol_id) REFERENCES symbols(id)
"threadfk" FOREIGN KEY (thread_id) REFERENCES threads(id)
"todsofk" FOREIGN KEY (to_dso_id) REFERENCES dsos(id)
"tosymbolfk" FOREIGN KEY (to_symbol_id) REFERENCES symbols(id)
lsdb-# \d samples_view
View "public.samples_view"
Column | Type | Modifiers
-------------------+-------------------------+-----------
id | bigint |
time | bigint |
cpu | integer |
pid | integer |
tid | integer |
command | character varying(16) |
event | character varying(80) |
ip_hex | text |
symbol | character varying(2048) |
sym_offset | bigint |
dso_short_name | character varying(256) |
to_ip_hex | text |
to_symbol | character varying(2048) |
to_sym_offset | bigint |
to_dso_short_name | character varying(256) |
lsdb=# select * from samples_view;
id| time |cpu | pid | tid |command| event | ip_hex | symbol |sym_off| dso_name|to_ip_hex|to_symbol|to_sym_off|to_dso_name
--+------------+----+------+------+-------+--------+---------------+---------------------+-------+---------+---------+---------+----------+----------
1 |12202825015 | -1 | 7339 | 7339 |:17339 | cycles | fffff8104d24a |native_write_msr_safe| 10 | [kernel]| 0 | unknown | 0| unknown
2 |12203258804 | -1 | 7339 | 7339 |:17339 | cycles | fffff8104d24a |native_write_msr_safe| 10 | [kernel]| 0 | unknown | 0| unknown
3 |12203988119 | -1 | 7339 | 7339 |:17339 | cycles | fffff8104d24a |native_write_msr_safe| 10 | [kernel]| 0 | unknown | 0| unknown
My notes (which may be out-of-date) on setting up postgresql so you can
create databases:
fedora:
$ sudo yum install postgresql postgresql-server python-pyside qt-postgresql
$ sudo su - postgres -c initdb
$ sudo service postgresql start
$ sudo su - postgres
$ createuser -s <your username>
I used the the unix user name in createuser.
If it fails, try createuser without -s and answer the following question
to allow your user to create tables:
Shall the new role be a superuser? (y/n) y
ubuntu:
$ sudo apt-get install postgresql
$ sudo su - postgres
$ createuser <your username>
Shall the new role be a superuser? (y/n) y
You may want to disable automatic startup. One way is to edit
/etc/postgresql/9.3/main/start.conf. Another is to disable the init
script e.g. sudo update-rc.d postgresql disable
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1414061124-26830-8-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
3 files changed, 392 insertions, 0 deletions
diff --git a/tools/perf/scripts/python/bin/export-to-postgresql-record b/tools/perf/scripts/python/bin/export-to-postgresql-record new file mode 100644 index 000000000000..221d66e05713 --- /dev/null +++ b/tools/perf/scripts/python/bin/export-to-postgresql-record | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | |||
| 3 | # | ||
| 4 | # export perf data to a postgresql database. Can cover | ||
| 5 | # perf ip samples (excluding the tracepoints). No special | ||
| 6 | # record requirements, just record what you want to export. | ||
| 7 | # | ||
| 8 | perf record $@ | ||
diff --git a/tools/perf/scripts/python/bin/export-to-postgresql-report b/tools/perf/scripts/python/bin/export-to-postgresql-report new file mode 100644 index 000000000000..a8fdd15f85bf --- /dev/null +++ b/tools/perf/scripts/python/bin/export-to-postgresql-report | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | # description: export perf data to a postgresql database | ||
| 3 | # args: [database name] [columns] | ||
| 4 | n_args=0 | ||
| 5 | for i in "$@" | ||
| 6 | do | ||
| 7 | if expr match "$i" "-" > /dev/null ; then | ||
| 8 | break | ||
| 9 | fi | ||
| 10 | n_args=$(( $n_args + 1 )) | ||
| 11 | done | ||
| 12 | if [ "$n_args" -gt 2 ] ; then | ||
| 13 | echo "usage: export-to-postgresql-report [database name] [columns]" | ||
| 14 | exit | ||
| 15 | fi | ||
| 16 | if [ "$n_args" -gt 1 ] ; then | ||
| 17 | dbname=$1 | ||
| 18 | columns=$2 | ||
| 19 | shift 2 | ||
| 20 | elif [ "$n_args" -gt 0 ] ; then | ||
| 21 | dbname=$1 | ||
| 22 | shift | ||
| 23 | fi | ||
| 24 | perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/export-to-postgresql.py $dbname $columns | ||
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py new file mode 100644 index 000000000000..d8f6df0093d6 --- /dev/null +++ b/tools/perf/scripts/python/export-to-postgresql.py | |||
| @@ -0,0 +1,360 @@ | |||
| 1 | # export-to-postgresql.py: export perf data to a postgresql database | ||
| 2 | # Copyright (c) 2014, Intel Corporation. | ||
| 3 | # | ||
| 4 | # This program is free software; you can redistribute it and/or modify it | ||
| 5 | # under the terms and conditions of the GNU General Public License, | ||
| 6 | # version 2, as published by the Free Software Foundation. | ||
| 7 | # | ||
| 8 | # This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | # more details. | ||
| 12 | |||
| 13 | import os | ||
| 14 | import sys | ||
| 15 | import struct | ||
| 16 | import datetime | ||
| 17 | |||
| 18 | from PySide.QtSql import * | ||
| 19 | |||
| 20 | # Need to access PostgreSQL C library directly to use COPY FROM STDIN | ||
| 21 | from ctypes import * | ||
| 22 | libpq = CDLL("libpq.so.5") | ||
| 23 | PQconnectdb = libpq.PQconnectdb | ||
| 24 | PQconnectdb.restype = c_void_p | ||
| 25 | PQfinish = libpq.PQfinish | ||
| 26 | PQstatus = libpq.PQstatus | ||
| 27 | PQexec = libpq.PQexec | ||
| 28 | PQexec.restype = c_void_p | ||
| 29 | PQresultStatus = libpq.PQresultStatus | ||
| 30 | PQputCopyData = libpq.PQputCopyData | ||
| 31 | PQputCopyData.argtypes = [ c_void_p, c_void_p, c_int ] | ||
| 32 | PQputCopyEnd = libpq.PQputCopyEnd | ||
| 33 | PQputCopyEnd.argtypes = [ c_void_p, c_void_p ] | ||
| 34 | |||
| 35 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | ||
| 36 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | ||
| 37 | |||
| 38 | # These perf imports are not used at present | ||
| 39 | #from perf_trace_context import * | ||
| 40 | #from Core import * | ||
| 41 | |||
| 42 | perf_db_export_mode = True | ||
| 43 | |||
| 44 | def usage(): | ||
| 45 | print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>]" | ||
| 46 | print >> sys.stderr, "where: columns 'all' or 'branches'" | ||
| 47 | raise Exception("Too few arguments") | ||
| 48 | |||
| 49 | if (len(sys.argv) < 2): | ||
| 50 | usage() | ||
| 51 | |||
| 52 | dbname = sys.argv[1] | ||
| 53 | |||
| 54 | if (len(sys.argv) >= 3): | ||
| 55 | columns = sys.argv[2] | ||
| 56 | else: | ||
| 57 | columns = "all" | ||
| 58 | |||
| 59 | if columns not in ("all", "branches"): | ||
| 60 | usage() | ||
| 61 | |||
| 62 | branches = (columns == "branches") | ||
| 63 | |||
| 64 | output_dir_name = os.getcwd() + "/" + dbname + "-perf-data" | ||
| 65 | os.mkdir(output_dir_name) | ||
| 66 | |||
| 67 | def do_query(q, s): | ||
| 68 | if (q.exec_(s)): | ||
| 69 | return | ||
| 70 | raise Exception("Query failed: " + q.lastError().text()) | ||
| 71 | |||
| 72 | print datetime.datetime.today(), "Creating database..." | ||
| 73 | |||
| 74 | db = QSqlDatabase.addDatabase('QPSQL') | ||
| 75 | query = QSqlQuery(db) | ||
| 76 | db.setDatabaseName('postgres') | ||
| 77 | db.open() | ||
| 78 | try: | ||
| 79 | do_query(query, 'CREATE DATABASE ' + dbname) | ||
| 80 | except: | ||
| 81 | os.rmdir(output_dir_name) | ||
| 82 | raise | ||
| 83 | query.finish() | ||
| 84 | query.clear() | ||
| 85 | db.close() | ||
| 86 | |||
| 87 | db.setDatabaseName(dbname) | ||
| 88 | db.open() | ||
| 89 | |||
| 90 | query = QSqlQuery(db) | ||
| 91 | do_query(query, 'SET client_min_messages TO WARNING') | ||
| 92 | |||
| 93 | do_query(query, 'CREATE TABLE selected_events (' | ||
| 94 | 'id bigint NOT NULL,' | ||
| 95 | 'name varchar(80))') | ||
| 96 | do_query(query, 'CREATE TABLE machines (' | ||
| 97 | 'id bigint NOT NULL,' | ||
| 98 | 'pid integer,' | ||
| 99 | 'root_dir varchar(4096))') | ||
| 100 | do_query(query, 'CREATE TABLE threads (' | ||
| 101 | 'id bigint NOT NULL,' | ||
| 102 | 'machine_id bigint,' | ||
| 103 | 'process_id bigint,' | ||
| 104 | 'pid integer,' | ||
| 105 | 'tid integer)') | ||
| 106 | do_query(query, 'CREATE TABLE comms (' | ||
| 107 | 'id bigint NOT NULL,' | ||
| 108 | 'comm varchar(16))') | ||
| 109 | do_query(query, 'CREATE TABLE comm_threads (' | ||
| 110 | 'id bigint NOT NULL,' | ||
| 111 | 'comm_id bigint,' | ||
| 112 | 'thread_id bigint)') | ||
| 113 | do_query(query, 'CREATE TABLE dsos (' | ||
| 114 | 'id bigint NOT NULL,' | ||
| 115 | 'machine_id bigint,' | ||
| 116 | 'short_name varchar(256),' | ||
| 117 | 'long_name varchar(4096),' | ||
| 118 | 'build_id varchar(64))') | ||
| 119 | do_query(query, 'CREATE TABLE symbols (' | ||
| 120 | 'id bigint NOT NULL,' | ||
| 121 | 'dso_id bigint,' | ||
| 122 | 'sym_start bigint,' | ||
| 123 | 'sym_end bigint,' | ||
| 124 | 'binding integer,' | ||
