|
|
d5df0a |
commit ebde58121d34e30f57ab173bf425244ce0712d48
|
|
|
d5df0a |
Author: Maynard Johnson <maynardj@us.ibm.com>
|
|
|
d5df0a |
Date: Wed Oct 9 13:12:21 2013 -0500
|
|
|
d5df0a |
|
|
|
d5df0a |
Converge operf and ocount utility functions
|
|
|
d5df0a |
|
|
|
d5df0a |
When the ocount tool was developed, a number of utility
|
|
|
d5df0a |
functions were needed that were very similar to operf utility
|
|
|
d5df0a |
functions, with just minor changes. The decision was made at
|
|
|
d5df0a |
the time to copy these functions into ocount and change them
|
|
|
d5df0a |
as needed. To avoid dual maintenance on very similar functions,
|
|
|
d5df0a |
we should converge the two tools to use one common set of utility
|
|
|
d5df0a |
functions. The main reason for not doing so in the first place
|
|
|
d5df0a |
was to make it easier to review ocount patches and not have to
|
|
|
d5df0a |
look at operf changes at the same time.
|
|
|
d5df0a |
|
|
|
d5df0a |
Signed-off-by: Maynard Johnson <maynardj@us.ibm.com>
|
|
|
d5df0a |
|
|
|
d5df0a |
diff --git a/Makefile.am b/Makefile.am
|
|
|
d5df0a |
index 293114b..2fe8d2f 100644
|
|
|
d5df0a |
--- a/Makefile.am
|
|
|
d5df0a |
+++ b/Makefile.am
|
|
|
d5df0a |
@@ -19,9 +19,9 @@ SUBDIRS = \
|
|
|
d5df0a |
events \
|
|
|
d5df0a |
doc \
|
|
|
d5df0a |
gui \
|
|
|
d5df0a |
+ libpe_utils \
|
|
|
d5df0a |
libperf_events \
|
|
|
d5df0a |
pe_profiling \
|
|
|
d5df0a |
- libpe_utils \
|
|
|
d5df0a |
pe_counting \
|
|
|
d5df0a |
agents
|
|
|
d5df0a |
#### ATTENTION ####
|
|
|
d5df0a |
diff --git a/libpe_utils/op_pe_utils.cpp b/libpe_utils/op_pe_utils.cpp
|
|
|
d5df0a |
index dc9459e..b85d175 100644
|
|
|
d5df0a |
--- a/libpe_utils/op_pe_utils.cpp
|
|
|
d5df0a |
+++ b/libpe_utils/op_pe_utils.cpp
|
|
|
d5df0a |
@@ -52,7 +52,9 @@ extern op_cpu cpu_type;
|
|
|
d5df0a |
|
|
|
d5df0a |
using namespace std;
|
|
|
d5df0a |
|
|
|
d5df0a |
-static int _op_get_next_online_cpu(DIR * dir, struct dirent *entry)
|
|
|
d5df0a |
+// Global functions
|
|
|
d5df0a |
+
|
|
|
d5df0a |
+int op_pe_utils::op_get_next_online_cpu(DIR * dir, struct dirent *entry)
|
|
|
d5df0a |
{
|
|
|
d5df0a |
#define OFFLINE 0x30
|
|
|
d5df0a |
unsigned int cpu_num;
|
|
|
d5df0a |
@@ -86,8 +88,6 @@ static int _op_get_next_online_cpu(DIR * dir, struct dirent *entry)
|
|
|
d5df0a |
return cpu_num;
|
|
|
d5df0a |
}
|
|
|
d5df0a |
|
|
|
d5df0a |
-// Global functions
|
|
|
d5df0a |
-
|
|
|
d5df0a |
int op_pe_utils::op_get_sys_value(const char * filename)
|
|
|
d5df0a |
{
|
|
|
d5df0a |
char str[10];
|
|
|
d5df0a |
@@ -148,7 +148,7 @@ int op_pe_utils::op_get_cpu_for_perf_events_cap(void)
|
|
|
d5df0a |
goto error;
|
|
|
d5df0a |
} else {
|
|
|
d5df0a |
struct dirent *entry = NULL;
|
|
|
d5df0a |
- retval = _op_get_next_online_cpu(dir, entry);
|
|
|
d5df0a |
+ retval = op_get_next_online_cpu(dir, entry);
|
|
|
d5df0a |
closedir(dir);
|
|
|
d5df0a |
}
|
|
|
d5df0a |
} else {
|
|
|
d5df0a |
@@ -310,40 +310,6 @@ int op_pe_utils::op_validate_app_name(char ** app, char ** save_appname)
|
|
|
d5df0a |
|
|
|
d5df0a |
out: return rc;
|
|
|
d5df0a |
}
|
|
|
d5df0a |
-static int _get_next_online_cpu(DIR * dir, struct dirent *entry)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
-#define OFFLINE 0x30
|
|
|
d5df0a |
- unsigned int cpu_num;
|
|
|
d5df0a |
- char cpu_online_pathname[40];
|
|
|
d5df0a |
- int res;
|
|
|
d5df0a |
- FILE * online;
|
|
|
d5df0a |
- again:
|
|
|
d5df0a |
- do {
|
|
|
d5df0a |
- entry = readdir(dir);
|
|
|
d5df0a |
- if (!entry)
|
|
|
d5df0a |
- return -1;
|
|
|
d5df0a |
- } while (entry->d_type != DT_DIR);
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- res = sscanf(entry->d_name, "cpu%u", &cpu_num);
|
|
|
d5df0a |
- if (res <= 0)
|
|
|
d5df0a |
- goto again;
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- errno = 0;
|
|
|
d5df0a |
- snprintf(cpu_online_pathname, 40, "/sys/devices/system/cpu/cpu%u/online", cpu_num);
|
|
|
d5df0a |
- if ((online = fopen(cpu_online_pathname, "r")) == NULL) {
|
|
|
d5df0a |
- cerr << "Unable to open " << cpu_online_pathname << endl;
|
|
|
d5df0a |
- if (errno)
|
|
|
d5df0a |
- cerr << strerror(errno) << endl;
|
|
|
d5df0a |
- return -1;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- res = fgetc(online);
|
|
|
d5df0a |
- fclose(online);
|
|
|
d5df0a |
- if (res == OFFLINE)
|
|
|
d5df0a |
- goto again;
|
|
|
d5df0a |
- else
|
|
|
d5df0a |
- return cpu_num;
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-
|
|
|
d5df0a |
|
|
|
d5df0a |
set<int> op_pe_utils::op_get_available_cpus(int max_num_cpus)
|
|
|
d5df0a |
{
|
|
|
d5df0a |
@@ -392,7 +358,7 @@ set<int> op_pe_utils::op_get_available_cpus(int max_num_cpus)
|
|
|
d5df0a |
if (all_cpus_avail) {
|
|
|
d5df0a |
available_cpus.insert(cpu);
|
|
|
d5df0a |
} else {
|
|
|
d5df0a |
- real_cpu = _get_next_online_cpu(dir, entry);
|
|
|
d5df0a |
+ real_cpu = op_get_next_online_cpu(dir, entry);
|
|
|
d5df0a |
if (real_cpu < 0) {
|
|
|
d5df0a |
err_msg = "Internal Error: Number of online cpus cannot be determined.";
|
|
|
d5df0a |
rc = -1;
|
|
|
d5df0a |
@@ -803,7 +769,8 @@ static bool convert_event_vals(vector<operf_event_t> * evt_vec)
|
|
|
d5df0a |
|
|
|
d5df0a |
|
|
|
d5df0a |
|
|
|
d5df0a |
-void op_pe_utils::op_process_events_list(vector<string> & passed_evts)
|
|
|
d5df0a |
+void op_pe_utils::op_process_events_list(vector<string> & passed_evts,
|
|
|
d5df0a |
+ bool do_profiling, bool do_callgraph)
|
|
|
d5df0a |
{
|
|
|
d5df0a |
string cmd = OP_BINDIR;
|
|
|
d5df0a |
|
|
|
d5df0a |
@@ -812,7 +779,9 @@ void op_pe_utils::op_process_events_list(vector<string> & passed_evts)
|
|
|
d5df0a |
<< OP_MAX_EVENTS << "." << endl;
|
|
|
d5df0a |
exit(EXIT_FAILURE);
|
|
|
d5df0a |
}
|
|
|
d5df0a |
- cmd += "/ophelp --check-events --ignore-count ";
|
|
|
d5df0a |
+ cmd += "/ophelp --check-events ";
|
|
|
d5df0a |
+ if (!do_profiling)
|
|
|
d5df0a |
+ cmd += "--ignore-count ";
|
|
|
d5df0a |
for (unsigned int i = 0; i < passed_evts.size(); i++) {
|
|
|
d5df0a |
FILE * fp;
|
|
|
d5df0a |
string full_cmd = cmd;
|
|
|
d5df0a |
@@ -825,6 +794,8 @@ void op_pe_utils::op_process_events_list(vector<string> & passed_evts)
|
|
|
d5df0a |
event_spec = _handle_powerpc_event_spec(event_spec);
|
|
|
d5df0a |
#endif
|
|
|
d5df0a |
|
|
|
d5df0a |
+ if (do_callgraph)
|
|
|
d5df0a |
+ full_cmd += " --callgraph=1 ";
|
|
|
d5df0a |
full_cmd += event_spec;
|
|
|
d5df0a |
fp = popen(full_cmd.c_str(), "r");
|
|
|
d5df0a |
if (fp == NULL) {
|
|
|
d5df0a |
@@ -836,14 +807,21 @@ void op_pe_utils::op_process_events_list(vector<string> & passed_evts)
|
|
|
d5df0a |
pclose(fp);
|
|
|
d5df0a |
cerr << "Error retrieving info for event "
|
|
|
d5df0a |
<< event_spec << endl;
|
|
|
d5df0a |
+ if (do_callgraph)
|
|
|
d5df0a |
+ cerr << "Note: When doing callgraph profiling, the sample count must be"
|
|
|
d5df0a |
+ << endl << "15 times the minimum count value for the event." << endl;
|
|
|
d5df0a |
exit(EXIT_FAILURE);
|
|
|
d5df0a |
}
|
|
|
d5df0a |
pclose(fp);
|
|
|
d5df0a |
char * event_str = op_xstrndup(event_spec.c_str(), event_spec.length());
|
|
|
d5df0a |
operf_event_t event;
|
|
|
d5df0a |
strncpy(event.name, strtok(event_str, ":"), OP_MAX_EVT_NAME_LEN - 1);
|
|
|
d5df0a |
+ if (do_profiling)
|
|
|
d5df0a |
+ event.count = atoi(strtok(NULL, ":"));
|
|
|
d5df0a |
+ else
|
|
|
d5df0a |
+ event.count = 0UL;
|
|
|
d5df0a |
/* Event name is required in the event spec in order for
|
|
|
d5df0a |
- * 'ophelp --check-events --ignore-count' to pass. But since unit mask
|
|
|
d5df0a |
+ * 'ophelp --check-events' to pass. But since unit mask
|
|
|
d5df0a |
* and domain control bits are optional, we need to ensure the result of
|
|
|
d5df0a |
* strtok is valid.
|
|
|
d5df0a |
*/
|
|
|
d5df0a |
@@ -854,7 +832,6 @@ void op_pe_utils::op_process_events_list(vector<string> & passed_evts)
|
|
|
d5df0a |
int place = _OP_UM;
|
|
|
d5df0a |
char * endptr = NULL;
|
|
|
d5df0a |
event.evt_um = 0UL;
|
|
|
d5df0a |
- event.count = 0UL;
|
|
|
d5df0a |
event.no_kernel = 0;
|
|
|
d5df0a |
event.no_user = 0;
|
|
|
d5df0a |
event.throttled = false;
|
|
|
d5df0a |
@@ -904,7 +881,7 @@ void op_pe_utils::op_process_events_list(vector<string> & passed_evts)
|
|
|
d5df0a |
#endif
|
|
|
d5df0a |
}
|
|
|
d5df0a |
|
|
|
d5df0a |
-void op_pe_utils::op_get_default_event(void)
|
|
|
d5df0a |
+void op_pe_utils::op_get_default_event(bool do_callgraph)
|
|
|
d5df0a |
{
|
|
|
d5df0a |
operf_event_t dft_evt;
|
|
|
d5df0a |
struct op_default_event_descr descr;
|
|
|
d5df0a |
@@ -918,7 +895,18 @@ void op_pe_utils::op_get_default_event(void)
|
|
|
d5df0a |
}
|
|
|
d5df0a |
|
|
|
d5df0a |
memset(&dft_evt, 0, sizeof(dft_evt));
|
|
|
d5df0a |
- dft_evt.count = descr.count;
|
|
|
d5df0a |
+ if (do_callgraph) {
|
|
|
d5df0a |
+ struct op_event * _event;
|
|
|
d5df0a |
+ op_events(cpu_type);
|
|
|
d5df0a |
+ if ((_event = find_event_by_name(descr.name, 0, 0))) {
|
|
|
d5df0a |
+ dft_evt.count = _event->min_count * CALLGRAPH_MIN_COUNT_SCALE;
|
|
|
d5df0a |
+ } else {
|
|
|
d5df0a |
+ cerr << "Error getting event info for " << descr.name << endl;
|
|
|
d5df0a |
+ exit(EXIT_FAILURE);
|
|
|
d5df0a |
+ }
|
|
|
d5df0a |
+ } else {
|
|
|
d5df0a |
+ dft_evt.count = descr.count;
|
|
|
d5df0a |
+ }
|
|
|
d5df0a |
dft_evt.evt_um = descr.um;
|
|
|
d5df0a |
strncpy(dft_evt.name, descr.name, OP_MAX_EVT_NAME_LEN - 1);
|
|
|
d5df0a |
_get_event_code(&dft_evt, cpu_type);
|
|
|
d5df0a |
diff --git a/libpe_utils/op_pe_utils.h b/libpe_utils/op_pe_utils.h
|
|
|
d5df0a |
index 400eed3..08b6fae 100644
|
|
|
d5df0a |
--- a/libpe_utils/op_pe_utils.h
|
|
|
d5df0a |
+++ b/libpe_utils/op_pe_utils.h
|
|
|
d5df0a |
@@ -18,11 +18,13 @@
|
|
|
d5df0a |
#include <dirent.h>
|
|
|
d5df0a |
|
|
|
d5df0a |
#include <vector>
|
|
|
d5df0a |
+#include <set>
|
|
|
d5df0a |
|
|
|
d5df0a |
#include "op_cpu_type.h"
|
|
|
d5df0a |
|
|
|
d5df0a |
#define OP_APPNAME_LEN 1024
|
|
|
d5df0a |
#define OP_MAX_EVENTS 24
|
|
|
d5df0a |
+#define CALLGRAPH_MIN_COUNT_SCALE 15
|
|
|
d5df0a |
|
|
|
d5df0a |
/* A macro to be used for ppc64 architecture-specific code. The '__powerpc__' macro
|
|
|
d5df0a |
* is defined for both ppc64 and ppc32 architectures, so we must further qualify by
|
|
|
d5df0a |
@@ -38,8 +40,10 @@ extern int op_check_perf_events_cap(bool use_cpu_minus_one);
|
|
|
d5df0a |
extern int op_get_sys_value(const char * filename);
|
|
|
d5df0a |
extern int op_get_cpu_for_perf_events_cap(void);
|
|
|
d5df0a |
extern int op_validate_app_name(char ** app, char ** save_appname);
|
|
|
d5df0a |
-extern void op_get_default_event(void);
|
|
|
d5df0a |
-extern void op_process_events_list(std::vector<std::string> & passed_evts);
|
|
|
d5df0a |
+extern void op_get_default_event(bool do_callgraph);
|
|
|
d5df0a |
+extern void op_process_events_list(std::vector<std::string> & passed_evts,
|
|
|
d5df0a |
+ bool do_profiling, bool do_callgraph);
|
|
|
d5df0a |
+extern int op_get_next_online_cpu(DIR * dir, struct dirent *entry);
|
|
|
d5df0a |
extern std::set<int> op_get_available_cpus(int max_num_cpus);
|
|
|
d5df0a |
}
|
|
|
d5df0a |
|
|
|
d5df0a |
diff --git a/libperf_events/Makefile.am b/libperf_events/Makefile.am
|
|
|
d5df0a |
index 7163610..cf5f434 100644
|
|
|
d5df0a |
--- a/libperf_events/Makefile.am
|
|
|
d5df0a |
+++ b/libperf_events/Makefile.am
|
|
|
d5df0a |
@@ -7,6 +7,7 @@ AM_CPPFLAGS = \
|
|
|
d5df0a |
-I ${top_srcdir}/libop \
|
|
|
d5df0a |
-I ${top_srcdir}/libdb \
|
|
|
d5df0a |
-I ${top_srcdir}/libperf_events \
|
|
|
d5df0a |
+ -I ${top_srcdir}/libpe_utils \
|
|
|
d5df0a |
@PERF_EVENT_FLAGS@ \
|
|
|
d5df0a |
@OP_CPPFLAGS@
|
|
|
d5df0a |
|
|
|
d5df0a |
diff --git a/libperf_events/operf_counter.cpp b/libperf_events/operf_counter.cpp
|
|
|
d5df0a |
index b4cceaa..319e859 100644
|
|
|
d5df0a |
--- a/libperf_events/operf_counter.cpp
|
|
|
d5df0a |
+++ b/libperf_events/operf_counter.cpp
|
|
|
d5df0a |
@@ -31,6 +31,7 @@
|
|
|
d5df0a |
#include "operf_process_info.h"
|
|
|
d5df0a |
#include "op_libiberty.h"
|
|
|
d5df0a |
#include "operf_stats.h"
|
|
|
d5df0a |
+#include "op_pe_utils.h"
|
|
|
d5df0a |
|
|
|
d5df0a |
|
|
|
d5df0a |
using namespace std;
|
|
|
d5df0a |
@@ -645,7 +646,7 @@ void operf_record::setup()
|
|
|
d5df0a |
} else if (all_cpus_avail) {
|
|
|
d5df0a |
real_cpu = cpu;
|
|
|
d5df0a |
} else {
|
|
|
d5df0a |
- real_cpu = op_get_next_online_cpu(dir, entry);
|
|
|
d5df0a |
+ real_cpu = op_pe_utils::op_get_next_online_cpu(dir, entry);
|
|
|
d5df0a |
if (real_cpu < 0) {
|
|
|
d5df0a |
err_msg = "Internal Error: Number of online cpus cannot be determined.";
|
|
|
d5df0a |
rc = -1;
|
|
|
d5df0a |
diff --git a/libperf_events/operf_utils.cpp b/libperf_events/operf_utils.cpp
|
|
|
d5df0a |
index 30e64d8..faed9a6 100644
|
|
|
d5df0a |
--- a/libperf_events/operf_utils.cpp
|
|
|
d5df0a |
+++ b/libperf_events/operf_utils.cpp
|
|
|
d5df0a |
@@ -65,161 +65,6 @@ static list<event_t *> unresolved_events;
|
|
|
d5df0a |
static struct operf_transient trans;
|
|
|
d5df0a |
static bool sfile_init_done;
|
|
|
d5df0a |
|
|
|
d5df0a |
-/* Some architectures (e.g., ppc64) do not use the same event value (code) for oprofile
|
|
|
d5df0a |
- * and for perf_events. The operf-record process requires event values that perf_events
|
|
|
d5df0a |
- * understands, but the operf-read process requires oprofile event values. The purpose of
|
|
|
d5df0a |
- * the following method is to map the operf-record event value to a value that
|
|
|
d5df0a |
- * opreport can understand.
|
|
|
d5df0a |
- */
|
|
|
d5df0a |
-#if PPC64_ARCH
|
|
|
d5df0a |
-extern op_cpu cpu_type;
|
|
|
d5df0a |
-#define NIL_CODE ~0U
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-#if HAVE_LIBPFM3
|
|
|
d5df0a |
-static bool _get_codes_for_match(unsigned int pfm_idx, const char name[],
|
|
|
d5df0a |
- vector<operf_event_t> * evt_vec)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
- unsigned int num_events = evt_vec->size();
|
|
|
d5df0a |
- int tmp_code, ret;
|
|
|
d5df0a |
- char evt_name[OP_MAX_EVT_NAME_LEN];
|
|
|
d5df0a |
- unsigned int events_converted = 0;
|
|
|
d5df0a |
- for (unsigned int i = 0; i < num_events; i++) {
|
|
|
d5df0a |
- operf_event_t event = (*evt_vec)[i];
|
|
|
d5df0a |
- if (event.evt_code != NIL_CODE) {
|
|
|
d5df0a |
- events_converted++;
|
|
|
d5df0a |
- continue;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- memset(evt_name, 0, OP_MAX_EVT_NAME_LEN);
|
|
|
d5df0a |
- if (!strcmp(event.name, "CYCLES")) {
|
|
|
d5df0a |
- strcpy(evt_name ,"PM_CYC") ;
|
|
|
d5df0a |
- } else if (strstr(event.name, "_GRP")) {
|
|
|
d5df0a |
- string str = event.name;
|
|
|
d5df0a |
- strncpy(evt_name, event.name, str.rfind("_GRP"));
|
|
|
d5df0a |
- } else {
|
|
|
d5df0a |
- strncpy(evt_name, event.name, strlen(event.name));
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- if (strncmp(name, evt_name, OP_MAX_EVT_NAME_LEN))
|
|
|
d5df0a |
- continue;
|
|
|
d5df0a |
- ret = pfm_get_event_code(pfm_idx, &tmp_code);
|
|
|
d5df0a |
- if (ret != PFMLIB_SUCCESS) {
|
|
|
d5df0a |
- string evt_name_str = event.name;
|
|
|
d5df0a |
- string msg = "libpfm cannot find event code for " + evt_name_str +
|
|
|
d5df0a |
- "; cannot continue";
|
|
|
d5df0a |
- throw runtime_error(msg);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- event.evt_code = tmp_code;
|
|
|
d5df0a |
- (*evt_vec)[i] = event;
|
|
|
d5df0a |
- events_converted++;
|
|
|
d5df0a |
- cverb << vrecord << "Successfully converted " << event.name << " to perf_event code "
|
|
|
d5df0a |
- << hex << tmp_code << endl;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- return (events_converted == num_events);
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-#else
|
|
|
d5df0a |
-static bool _op_get_event_codes(vector<operf_event_t> * evt_vec)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
- int ret, i;
|
|
|
d5df0a |
- unsigned int num_events = evt_vec->size();
|
|
|
d5df0a |
- char evt_name[OP_MAX_EVT_NAME_LEN];
|
|
|
d5df0a |
- unsigned int events_converted = 0;
|
|
|
d5df0a |
- uint64_t code[1];
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- typedef struct {
|
|
|
d5df0a |
- uint64_t *codes;
|
|
|
d5df0a |
- char **fstr;
|
|
|
d5df0a |
- size_t size;
|
|
|
d5df0a |
- int count;
|
|
|
d5df0a |
- int idx;
|
|
|
d5df0a |
- } pfm_raw_pmu_encode_t;
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- pfm_raw_pmu_encode_t raw;
|
|
|
d5df0a |
- raw.codes = code;
|
|
|
d5df0a |
- raw.count = 1;
|
|
|
d5df0a |
- raw.fstr = NULL;
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- if (pfm_initialize() != PFM_SUCCESS)
|
|
|
d5df0a |
- throw runtime_error("Unable to initialize libpfm; cannot continue");
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- for (unsigned int i = 0; i < num_events; i++) {
|
|
|
d5df0a |
- operf_event_t event = (*evt_vec)[i];
|
|
|
d5df0a |
- if (event.evt_code != NIL_CODE) {
|
|
|
d5df0a |
- events_converted++;
|
|
|
d5df0a |
- continue;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- memset(evt_name, 0, OP_MAX_EVT_NAME_LEN);
|
|
|
d5df0a |
- if (!strcmp(event.name, "CYCLES")) {
|
|
|
d5df0a |
- strcpy(evt_name ,"PM_CYC") ;
|
|
|
d5df0a |
- } else if (strstr(event.name, "_GRP")) {
|
|
|
d5df0a |
- string str = event.name;
|
|
|
d5df0a |
- strncpy(evt_name, event.name, str.rfind("_GRP"));
|
|
|
d5df0a |
- } else {
|
|
|
d5df0a |
- strncpy(evt_name, event.name, strlen(event.name));
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- memset(&raw, 0, sizeof(raw));
|
|
|
d5df0a |
- ret = pfm_get_os_event_encoding(evt_name, PFM_PLM3, PFM_OS_NONE, &raw;;
|
|
|
d5df0a |
- if (ret != PFM_SUCCESS) {
|
|
|
d5df0a |
- string evt_name_str = event.name;
|
|
|
d5df0a |
- string msg = "libpfm cannot find event code for " + evt_name_str +
|
|
|
d5df0a |
- "; cannot continue";
|
|
|
d5df0a |
- throw runtime_error(msg);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- event.evt_code = raw.codes[0];
|
|
|
d5df0a |
- (*evt_vec)[i] = event;
|
|
|
d5df0a |
- events_converted++;
|
|
|
d5df0a |
- cverb << vrecord << "Successfully converted " << event.name << " to perf_event code "
|
|
|
d5df0a |
- << hex << event.evt_code << endl;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- return (events_converted == num_events);
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-#endif
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-bool OP_perf_utils::op_convert_event_vals(vector<operf_event_t> * evt_vec)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
- unsigned int i, count;
|
|
|
d5df0a |
- char name[256];
|
|
|
d5df0a |
- int ret;
|
|
|
d5df0a |
- for (unsigned int i = 0; i < evt_vec->size(); i++) {
|
|
|
d5df0a |
- operf_event_t event = (*evt_vec)[i];
|
|
|
d5df0a |
- if (cpu_type == CPU_PPC64_POWER7) {
|
|
|
d5df0a |
- if (!strncmp(event.name, "PM_RUN_CYC", strlen("PM_RUN_CYC"))) {
|
|
|
d5df0a |
- event.evt_code = 0x600f4;
|
|
|
d5df0a |
- } else if (!strncmp(event.name, "PM_RUN_INST_CMPL", strlen("PM_RUN_INST_CMPL"))) {
|
|
|
d5df0a |
- event.evt_code = 0x500fa;
|
|
|
d5df0a |
- } else {
|
|
|
d5df0a |
- event.evt_code = NIL_CODE;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- } else {
|
|
|
d5df0a |
- event.evt_code = NIL_CODE;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- (*evt_vec)[i] = event;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-#if HAVE_LIBPFM3
|
|
|
d5df0a |
- if (pfm_initialize() != PFMLIB_SUCCESS)
|
|
|
d5df0a |
- throw runtime_error("Unable to initialize libpfm; cannot continue");
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- ret = pfm_get_num_events(&count);
|
|
|
d5df0a |
- if (ret != PFMLIB_SUCCESS)
|
|
|
d5df0a |
- throw runtime_error("Unable to use libpfm to obtain event code; cannot continue");
|
|
|
d5df0a |
- for(i =0 ; i < count; i++)
|
|
|
d5df0a |
- {
|
|
|
d5df0a |
- ret = pfm_get_event_name(i, name, 256);
|
|
|
d5df0a |
- if (ret != PFMLIB_SUCCESS)
|
|
|
d5df0a |
- continue;
|
|
|
d5df0a |
- if (_get_codes_for_match(i, name, evt_vec))
|
|
|
d5df0a |
- break;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- return (i != count);
|
|
|
d5df0a |
-#else
|
|
|
d5df0a |
- return _op_get_event_codes(evt_vec);
|
|
|
d5df0a |
-#endif
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-#endif // PPC64_ARCH
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-
|
|
|
d5df0a |
static inline void update_trans_last(struct operf_transient * trans)
|
|
|
d5df0a |
{
|
|
|
d5df0a |
trans->last = trans->current;
|
|
|
d5df0a |
@@ -1465,38 +1310,3 @@ void OP_perf_utils::op_get_kernel_event_data(struct mmap_data *md, operf_record
|
|
|
d5df0a |
md->prev = old;
|
|
|
d5df0a |
pc->data_tail = old;
|
|
|
d5df0a |
}
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-int OP_perf_utils::op_get_next_online_cpu(DIR * dir, struct dirent *entry)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
-#define OFFLINE 0x30
|
|
|
d5df0a |
- unsigned int cpu_num;
|
|
|
d5df0a |
- char cpu_online_pathname[40];
|
|
|
d5df0a |
- int res;
|
|
|
d5df0a |
- FILE * online;
|
|
|
d5df0a |
- again:
|
|
|
d5df0a |
- do {
|
|
|
d5df0a |
- entry = readdir(dir);
|
|
|
d5df0a |
- if (!entry)
|
|
|
d5df0a |
- return -1;
|
|
|
d5df0a |
- } while (entry->d_type != DT_DIR);
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- res = sscanf(entry->d_name, "cpu%u", &cpu_num);
|
|
|
d5df0a |
- if (res <= 0)
|
|
|
d5df0a |
- goto again;
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- errno = 0;
|
|
|
d5df0a |
- snprintf(cpu_online_pathname, 40, "/sys/devices/system/cpu/cpu%u/online", cpu_num);
|
|
|
d5df0a |
- if ((online = fopen(cpu_online_pathname, "r")) == NULL) {
|
|
|
d5df0a |
- cerr << "Unable to open " << cpu_online_pathname << endl;
|
|
|
d5df0a |
- if (errno)
|
|
|
d5df0a |
- cerr << strerror(errno) << endl;
|
|
|
d5df0a |
- return -1;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- res = fgetc(online);
|
|
|
d5df0a |
- fclose(online);
|
|
|
d5df0a |
- if (res == OFFLINE)
|
|
|
d5df0a |
- goto again;
|
|
|
d5df0a |
- else
|
|
|
d5df0a |
- return cpu_num;
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
diff --git a/libperf_events/operf_utils.h b/libperf_events/operf_utils.h
|
|
|
d5df0a |
index 4c191fe..2a979e3 100644
|
|
|
d5df0a |
--- a/libperf_events/operf_utils.h
|
|
|
d5df0a |
+++ b/libperf_events/operf_utils.h
|
|
|
d5df0a |
@@ -87,8 +87,6 @@ int op_write_output(int output, void *buf, size_t size);
|
|
|
d5df0a |
int op_write_event(event_t * event, u64 sample_type);
|
|
|
d5df0a |
int op_read_from_stream(std::ifstream & is, char * buf, std::streamsize sz);
|
|
|
d5df0a |
int op_mmap_trace_file(struct mmap_info & info, bool init);
|
|
|
d5df0a |
-int op_get_next_online_cpu(DIR * dir, struct dirent *entry);
|
|
|
d5df0a |
-bool op_convert_event_vals(std::vector<operf_event_t> * evt_vec);
|
|
|
d5df0a |
void op_reprocess_unresolved_events(u64 sample_type, bool print_progress);
|
|
|
d5df0a |
void op_release_resources(void);
|
|
|
d5df0a |
}
|
|
|
d5df0a |
diff --git a/pe_counting/ocount.cpp b/pe_counting/ocount.cpp
|
|
|
d5df0a |
index 5a85c3f..db847ea 100644
|
|
|
d5df0a |
--- a/pe_counting/ocount.cpp
|
|
|
d5df0a |
+++ b/pe_counting/ocount.cpp
|
|
|
d5df0a |
@@ -720,9 +720,9 @@ static void process_args(int argc, char * const argv[])
|
|
|
d5df0a |
|
|
|
d5df0a |
if (ocount_options::evts.empty()) {
|
|
|
d5df0a |
// Use default event
|
|
|
d5df0a |
- op_pe_utils::op_get_default_event();
|
|
|
d5df0a |
+ op_pe_utils::op_get_default_event(false);
|
|
|
d5df0a |
} else {
|
|
|
d5df0a |
- op_pe_utils::op_process_events_list(ocount_options::evts);
|
|
|
d5df0a |
+ op_pe_utils::op_process_events_list(ocount_options::evts, false, false);
|
|
|
d5df0a |
}
|
|
|
d5df0a |
cverb << vdebug << "Number of events passed is " << events.size() << endl;
|
|
|
d5df0a |
return;
|
|
|
d5df0a |
diff --git a/pe_profiling/Makefile.am b/pe_profiling/Makefile.am
|
|
|
d5df0a |
index b27cbc7..8c232c4 100644
|
|
|
d5df0a |
--- a/pe_profiling/Makefile.am
|
|
|
d5df0a |
+++ b/pe_profiling/Makefile.am
|
|
|
d5df0a |
@@ -6,6 +6,7 @@ AM_CPPFLAGS = \
|
|
|
d5df0a |
-I ${top_srcdir}/libop \
|
|
|
d5df0a |
-I ${top_srcdir}/libutil++ \
|
|
|
d5df0a |
-I ${top_srcdir}/libperf_events \
|
|
|
d5df0a |
+ -I ${top_srcdir}/libpe_utils \
|
|
|
d5df0a |
@PERF_EVENT_FLAGS@ \
|
|
|
d5df0a |
@OP_CPPFLAGS@
|
|
|
d5df0a |
|
|
|
d5df0a |
@@ -15,7 +16,8 @@ AM_CXXFLAGS = @OP_CXXFLAGS@
|
|
|
d5df0a |
AM_LDFLAGS = @OP_LDFLAGS@
|
|
|
d5df0a |
|
|
|
d5df0a |
bin_PROGRAMS = operf
|
|
|
d5df0a |
-operf_LDADD = ../libperf_events/libperf_events.a \
|
|
|
d5df0a |
+operf_LDADD = ../libperf_events/libperf_events.a \
|
|
|
d5df0a |
+ ../libpe_utils/libpe_utils.a \
|
|
|
d5df0a |
../libutil++/libutil++.a \
|
|
|
d5df0a |
../libdb/libodb.a \
|
|
|
d5df0a |
../libop/libop.a \
|
|
|
d5df0a |
diff --git a/pe_profiling/operf.cpp b/pe_profiling/operf.cpp
|
|
|
d5df0a |
index 3fec123..89e9c4b 100644
|
|
|
d5df0a |
--- a/pe_profiling/operf.cpp
|
|
|
d5df0a |
+++ b/pe_profiling/operf.cpp
|
|
|
d5df0a |
@@ -35,6 +35,7 @@
|
|
|
d5df0a |
#include <getopt.h>
|
|
|
d5df0a |
#include <iostream>
|
|
|
d5df0a |
#include "operf_utils.h"
|
|
|
d5df0a |
+#include "op_pe_utils.h"
|
|
|
d5df0a |
#include "op_libiberty.h"
|
|
|
d5df0a |
#include "string_manip.h"
|
|
|
d5df0a |
#include "cverb.h"
|
|
|
d5df0a |
@@ -50,6 +51,7 @@
|
|
|
d5df0a |
#include "op_netburst.h"
|
|
|
d5df0a |
|
|
|
d5df0a |
using namespace std;
|
|
|
d5df0a |
+using namespace op_pe_utils;
|
|
|
d5df0a |
|
|
|
d5df0a |
typedef enum END_CODE {
|
|
|
d5df0a |
ALL_OK = 0,
|
|
|
d5df0a |
@@ -73,11 +75,11 @@ uid_t my_uid;
|
|
|
d5df0a |
bool no_vmlinux;
|
|
|
d5df0a |
int kptr_restrict;
|
|
|
d5df0a |
char * start_time_human_readable;
|
|
|
d5df0a |
+std::vector<operf_event_t> events;
|
|
|
d5df0a |
+
|
|
|
d5df0a |
|
|
|
d5df0a |
#define DEFAULT_OPERF_OUTFILE "operf.data"
|
|
|
d5df0a |
-#define CALLGRAPH_MIN_COUNT_SCALE 15
|
|
|
d5df0a |
|
|
|
d5df0a |
-static char full_pathname[PATH_MAX];
|
|
|
d5df0a |
static char * app_name_SAVE = NULL;
|
|
|
d5df0a |
static char ** app_args = NULL;
|
|
|
d5df0a |
static pid_t jitconv_pid = -1;
|
|
|
d5df0a |
@@ -88,7 +90,6 @@ static string samples_dir;
|
|
|
d5df0a |
static bool startApp;
|
|
|
d5df0a |
static string outputfile;
|
|
|
d5df0a |
static char start_time_str[32];
|
|
|
d5df0a |
-static vector<operf_event_t> events;
|
|
|
d5df0a |
static bool jit_conversion_running;
|
|
|
d5df0a |
static void convert_sample_data(void);
|
|
|
d5df0a |
static int sample_data_pipe[2];
|
|
|
d5df0a |
@@ -948,517 +949,6 @@ out:
|
|
|
d5df0a |
}
|
|
|
d5df0a |
|
|
|
d5df0a |
|
|
|
d5df0a |
-static int find_app_file_in_dir(const struct dirent * d)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
- if (!strcmp(d->d_name, app_name))
|
|
|
d5df0a |
- return 1;
|
|
|
d5df0a |
- else
|
|
|
d5df0a |
- return 0;
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-static int get_PATH_based_pathname(char * path_holder, size_t n)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
- int retval = -1;
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- char * real_path = getenv("PATH");
|
|
|
d5df0a |
- char * path = (char *) xstrdup(real_path);
|
|
|
d5df0a |
- char * segment = strtok(path, ":");
|
|
|
d5df0a |
- while (segment) {
|
|
|
d5df0a |
- struct dirent ** namelist;
|
|
|
d5df0a |
- int rc = scandir(segment, &namelist, find_app_file_in_dir, NULL);
|
|
|
d5df0a |
- if (rc < 0) {
|
|
|
d5df0a |
- if (errno != ENOENT) {
|
|
|
d5df0a |
- cerr << strerror(errno) << endl;
|
|
|
d5df0a |
- cerr << app_name << " cannot be found in your PATH." << endl;
|
|
|
d5df0a |
- break;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- } else if (rc == 1) {
|
|
|
d5df0a |
- size_t applen = strlen(app_name);
|
|
|
d5df0a |
- size_t dirlen = strlen(segment);
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- if (applen + dirlen + 2 > n) {
|
|
|
d5df0a |
- cerr << "Path segment " << segment
|
|
|
d5df0a |
- << " prepended to the passed app name is too long"
|
|
|
d5df0a |
- << endl;
|
|
|
d5df0a |
- retval = -1;
|
|
|
d5df0a |
- break;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- if (!strcmp(segment, ".")) {
|
|
|
d5df0a |
- if (getcwd(path_holder, PATH_MAX) == NULL) {
|
|
|
d5df0a |
- retval = -1;
|
|
|
d5df0a |
- cerr << "getcwd [3] failed when processing <cur-dir>/" << app_name << " found via PATH. Aborting."
|
|
|
d5df0a |
- << endl;
|
|
|
d5df0a |
- break;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- } else {
|
|
|
d5df0a |
- strncpy(path_holder, segment, dirlen);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- strcat(path_holder, "/");
|
|
|
d5df0a |
- strncat(path_holder, app_name, applen);
|
|
|
d5df0a |
- retval = 0;
|
|
|
d5df0a |
- free(namelist[0]);
|
|
|
d5df0a |
- free(namelist);
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- break;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- segment = strtok(NULL, ":");
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- free(path);
|
|
|
d5df0a |
- return retval;
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-int validate_app_name(void)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
- int rc = 0;
|
|
|
d5df0a |
- struct stat filestat;
|
|
|
d5df0a |
- size_t len = strlen(app_name);
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- if (len > (size_t) (OP_APPNAME_LEN - 1)) {
|
|
|
d5df0a |
- cerr << "app name longer than max allowed (" << OP_APPNAME_LEN
|
|
|
d5df0a |
- << " chars)\n";
|
|
|
d5df0a |
- cerr << app_name << endl;
|
|
|
d5df0a |
- rc = -1;
|
|
|
d5df0a |
- goto out;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- if (index(app_name, '/') == app_name) {
|
|
|
d5df0a |
- // Full pathname of app was specified, starting with "/".
|
|
|
d5df0a |
- strncpy(full_pathname, app_name, len);
|
|
|
d5df0a |
- } else if ((app_name[0] == '.') && (app_name[1] == '/')) {
|
|
|
d5df0a |
- // Passed app is in current directory; e.g., "./myApp"
|
|
|
d5df0a |
- if (getcwd(full_pathname, PATH_MAX) == NULL) {
|
|
|
d5df0a |
- rc = -1;
|
|
|
d5df0a |
- cerr << "getcwd [1] failed when trying to find app name " << app_name << ". Aborting."
|
|
|
d5df0a |
- << endl;
|
|
|
d5df0a |
- goto out;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- strcat(full_pathname, "/");
|
|
|
d5df0a |
- if ((strlen(full_pathname) + strlen(app_name + 2) + 1) > PATH_MAX) {
|
|
|
d5df0a |
- rc = -1;
|
|
|
d5df0a |
- cerr << "Length of current dir (" << full_pathname << ") and app name ("
|
|
|
d5df0a |
- << (app_name + 2) << ") exceeds max allowed (" << PATH_MAX << "). Aborting."
|
|
|
d5df0a |
- << endl;
|
|
|
d5df0a |
- goto out;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- strcat(full_pathname, (app_name + 2));
|
|
|
d5df0a |
- } else if (index(app_name, '/')) {
|
|
|
d5df0a |
- // Passed app is in a subdirectory of cur dir; e.g., "test-stuff/myApp"
|
|
|
d5df0a |
- if (getcwd(full_pathname, PATH_MAX) == NULL) {
|
|
|
d5df0a |
- rc = -1;
|
|
|
d5df0a |
- cerr << "getcwd [2] failed when trying to find app name " << app_name << ". Aborting."
|
|
|
d5df0a |
- << endl;
|
|
|
d5df0a |
- goto out;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- strcat(full_pathname, "/");
|
|
|
d5df0a |
- strcat(full_pathname, app_name);
|
|
|
d5df0a |
- } else {
|
|
|
d5df0a |
- // Passed app name, at this point, MUST be found in PATH
|
|
|
d5df0a |
- rc = get_PATH_based_pathname(full_pathname, PATH_MAX);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- if (rc) {
|
|
|
d5df0a |
- cerr << "Problem finding app name " << app_name << ". Aborting."
|
|
|
d5df0a |
- << endl;
|
|
|
d5df0a |
- goto out;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- app_name_SAVE = app_name;
|
|
|
d5df0a |
- app_name = full_pathname;
|
|
|
d5df0a |
- if (stat(app_name, &filestat)) {
|
|
|
d5df0a |
- char msg[OP_APPNAME_LEN + 50];
|
|
|
d5df0a |
- snprintf(msg, OP_APPNAME_LEN + 50, "Non-existent app name \"%s\"",
|
|
|
d5df0a |
- app_name);
|
|
|
d5df0a |
- perror(msg);
|
|
|
d5df0a |
- rc = -1;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- out: return rc;
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-static void _get_event_code(operf_event_t * event)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
- FILE * fp;
|
|
|
d5df0a |
- char oprof_event_code[9];
|
|
|
d5df0a |
- string command;
|
|
|
d5df0a |
- u64 base_code, config;
|
|
|
d5df0a |
- char buf[20];
|
|
|
d5df0a |
- if ((snprintf(buf, 20, "%lu", event->count)) < 0) {
|
|
|
d5df0a |
- cerr << "Error parsing event count of " << event->count << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- base_code = config = 0ULL;
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- command = OP_BINDIR;
|
|
|
d5df0a |
- command += "ophelp ";
|
|
|
d5df0a |
- command += event->name;
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- fp = popen(command.c_str(), "r");
|
|
|
d5df0a |
- if (fp == NULL) {
|
|
|
d5df0a |
- cerr << "Unable to execute ophelp to get info for event "
|
|
|
d5df0a |
- << event->name << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- if (fgets(oprof_event_code, sizeof(oprof_event_code), fp) == NULL) {
|
|
|
d5df0a |
- pclose(fp);
|
|
|
d5df0a |
- cerr << "Unable to find info for event "
|
|
|
d5df0a |
- << event->name << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- pclose(fp);
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- base_code = strtoull(oprof_event_code, (char **) NULL, 10);
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-#if defined(__i386__) || defined(__x86_64__)
|
|
|
d5df0a |
- // Setup EventSelct[11:8] field for AMD
|
|
|
d5df0a |
- char mask[12];
|
|
|
d5df0a |
- const char * vendor_AMD = "AuthenticAMD";
|
|
|
d5df0a |
- if (op_is_cpu_vendor((char *)vendor_AMD)) {
|
|
|
d5df0a |
- config = base_code & 0xF00ULL;
|
|
|
d5df0a |
- config = config << 32;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- // Setup EventSelct[7:0] field
|
|
|
d5df0a |
- config |= base_code & 0xFFULL;
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- // Setup unitmask field
|
|
|
d5df0a |
-handle_named_um:
|
|
|
d5df0a |
- if (event->um_name[0]) {
|
|
|
d5df0a |
- command = OP_BINDIR;
|
|
|
d5df0a |
- command += "ophelp ";
|
|
|
d5df0a |
- command += "--extra-mask ";
|
|
|
d5df0a |
- command += event->name;
|
|
|
d5df0a |
- command += ":";
|
|
|
d5df0a |
- command += buf;
|
|
|
d5df0a |
- command += ":";
|
|
|
d5df0a |
- command += event->um_name;
|
|
|
d5df0a |
- fp = popen(command.c_str(), "r");
|
|
|
d5df0a |
- if (fp == NULL) {
|
|
|
d5df0a |
- cerr << "Unable to execute ophelp to get info for event "
|
|
|
d5df0a |
- << event->name << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- if (fgets(mask, sizeof(mask), fp) == NULL) {
|
|
|
d5df0a |
- pclose(fp);
|
|
|
d5df0a |
- cerr << "Unable to find unit mask info for " << event->um_name << " for event "
|
|
|
d5df0a |
- << event->name << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- pclose(fp);
|
|
|
d5df0a |
- // FIXME: The mask value here is the extra bits from the named unit mask. It's not
|
|
|
d5df0a |
- // ideal to put that value into the UM's mask, since that's what will show up in
|
|
|
d5df0a |
- // opreport. It would be better if we could somehow have the unit mask name that the
|
|
|
d5df0a |
- // user passed to us show up in opreort.
|
|
|
d5df0a |
- event->evt_um = strtoull(mask, (char **) NULL, 10);
|
|
|
d5df0a |
- /* A value >= EXTRA_MIN_VAL returned by 'ophelp --extra-mask' is interpreted as a
|
|
|
d5df0a |
- * valid extra value; otherwise we interpret it as a simple unit mask value
|
|
|
d5df0a |
- * for a named unit mask with EXTRA_NONE.
|
|
|
d5df0a |
- */
|
|
|
d5df0a |
- if (event->evt_um >= EXTRA_MIN_VAL)
|
|
|
d5df0a |
- config |= event->evt_um;
|
|
|
d5df0a |
- else
|
|
|
d5df0a |
- config |= ((event->evt_um & 0xFFULL) << 8);
|
|
|
d5df0a |
- } else if (!event->evt_um) {
|
|
|
d5df0a |
- char * endptr;
|
|
|
d5df0a |
- command.clear();
|
|
|
d5df0a |
- command = OP_BINDIR;
|
|
|
d5df0a |
- command += "ophelp ";
|
|
|
d5df0a |
- command += "--unit-mask ";
|
|
|
d5df0a |
- command += event->name;
|
|
|
d5df0a |
- command += ":";
|
|
|
d5df0a |
- command += buf;
|
|
|
d5df0a |
- fp = popen(command.c_str(), "r");
|
|
|
d5df0a |
- if (fp == NULL) {
|
|
|
d5df0a |
- cerr << "Unable to execute ophelp to get unit mask for event "
|
|
|
d5df0a |
- << event->name << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- if (fgets(mask, sizeof(mask), fp) == NULL) {
|
|
|
d5df0a |
- pclose(fp);
|
|
|
d5df0a |
- cerr << "Unable to find unit mask info for event " << event->name << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- pclose(fp);
|
|
|
d5df0a |
- event->evt_um = strtoull(mask, &endptr, 10);
|
|
|
d5df0a |
- if ((endptr >= mask) &&
|
|
|
d5df0a |
- (endptr <= (mask + strlen(mask) - 1))) {
|
|
|
d5df0a |
- // Must be a default named unit mask
|
|
|
d5df0a |
- strncpy(event->um_name, mask, OP_MAX_UM_NAME_LEN);
|
|
|
d5df0a |
- goto handle_named_um;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- config |= ((event->evt_um & 0xFFULL) << 8);
|
|
|
d5df0a |
- } else {
|
|
|
d5df0a |
- config |= ((event->evt_um & 0xFFULL) << 8);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-#else
|
|
|
d5df0a |
- config = base_code;
|
|
|
d5df0a |
-#endif
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- event->op_evt_code = base_code;
|
|
|
d5df0a |
- if (cpu_type == CPU_P4 || cpu_type == CPU_P4_HT2) {
|
|
|
d5df0a |
- if (op_netburst_get_perf_encoding(event->name, event->evt_um, 1, 1, &config)) {
|
|
|
d5df0a |
- cerr << "Unable to get event encoding for " << event->name << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- event->evt_code = config;
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-#if PPC64_ARCH
|
|
|
d5df0a |
-/* All ppc64 events (except CYCLES) have a _GRP<n> suffix. This is
|
|
|
d5df0a |
- * because the legacy opcontrol profiler can only profile events in
|
|
|
d5df0a |
- * the same group (i.e., having the same _GRP<n> suffix). But operf
|
|
|
d5df0a |
- * can multiplex events, so we should allow the user to pass event
|
|
|
d5df0a |
- * names without the _GRP<n> suffix.
|
|
|
d5df0a |
- *
|
|
|
d5df0a |
- * If event name is not CYCLES or does not have a _GRP<n> suffix,
|
|
|
d5df0a |
- * we'll call ophelp and scan the list of events, searching for one
|
|
|
d5df0a |
- * that matches up to the _GRP<n> suffix. If we don't find a match,
|
|
|
d5df0a |
- * then we'll exit with the expected error message for invalid event name.
|
|
|
d5df0a |
- */
|
|
|
d5df0a |
-static string _handle_powerpc_event_spec(string event_spec)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
- FILE * fp;
|
|
|
d5df0a |
- char line[MAX_INPUT];
|
|
|
d5df0a |
- size_t grp_pos;
|
|
|
d5df0a |
- string evt, retval, err_msg;
|
|
|
d5df0a |
- size_t evt_name_len;
|
|
|
d5df0a |
- bool first_non_cyc_evt_found = false;
|
|
|
d5df0a |
- bool event_found = false;
|
|
|
d5df0a |
- char event_name[OP_MAX_EVT_NAME_LEN], event_spec_str[OP_MAX_EVT_NAME_LEN + 20], * count_str;
|
|
|
d5df0a |
- string cmd = OP_BINDIR;
|
|
|
d5df0a |
- cmd += "/ophelp";
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- strncpy(event_spec_str, event_spec.c_str(), event_spec.length() + 1);
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- strncpy(event_name, strtok(event_spec_str, ":"), OP_MAX_EVT_NAME_LEN);
|
|
|
d5df0a |
- count_str = strtok(NULL, ":");
|
|
|
d5df0a |
- if (!count_str) {
|
|
|
d5df0a |
- err_msg = "Invalid count for event ";
|
|
|
d5df0a |
- goto out;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- if (!strcmp("CYCLES", event_name)) {
|
|
|
d5df0a |
- event_found = true;
|
|
|
d5df0a |
- goto out;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- evt = event_name;
|
|
|
d5df0a |
- // Need to make sure the event name truly has a _GRP<n> suffix.
|
|
|
d5df0a |
- grp_pos = evt.rfind("_GRP");
|
|
|
d5df0a |
- if ((grp_pos != string::npos) && ((evt = evt.substr(grp_pos, string::npos))).length() > 4) {
|
|
|
d5df0a |
- char * end;
|
|
|
d5df0a |
- strtoul(evt.substr(4, string::npos).c_str(), &end, 0);
|
|
|
d5df0a |
- if (end && (*end == '\0')) {
|
|
|
d5df0a |
- // Valid group number found after _GRP, so we can skip to the end.
|
|
|
d5df0a |
- event_found = true;
|
|
|
d5df0a |
- goto out;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- // If we get here, it implies the user passed a non-CYCLES event without a GRP suffix.
|
|
|
d5df0a |
- // Lets try to find a valid suffix for it.
|
|
|
d5df0a |
- fp = popen(cmd.c_str(), "r");
|
|
|
d5df0a |
- if (fp == NULL) {
|
|
|
d5df0a |
- cerr << "Unable to execute ophelp to get info for event "
|
|
|
d5df0a |
- << event_spec << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- evt_name_len = strlen(event_name);
|
|
|
d5df0a |
- err_msg = "Cannot find event ";
|
|
|
d5df0a |
- while (fgets(line, MAX_INPUT, fp)) {
|
|
|
d5df0a |
- if (!first_non_cyc_evt_found) {
|
|
|
d5df0a |
- if (!strncmp(line, "PM_", 3))
|
|
|
d5df0a |
- first_non_cyc_evt_found = true;
|
|
|
d5df0a |
- else
|
|
|
d5df0a |
- continue;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- if (line[0] == ' ' || line[0] == '\t')
|
|
|
d5df0a |
- continue;
|
|
|
d5df0a |
- if (!strncmp(line, event_name, evt_name_len)) {
|
|
|
d5df0a |
- // Found a potential match. Check if it's a perfect match.
|
|
|
d5df0a |
- string save_event_name = event_name;
|
|
|
d5df0a |
- size_t full_evt_len = index(line, ':') - line;
|
|
|
d5df0a |
- memset(event_name, '\0', OP_MAX_EVT_NAME_LEN);
|
|
|
d5df0a |
- strncpy(event_name, line, full_evt_len);
|
|
|
d5df0a |
- string candidate = event_name;
|
|
|
d5df0a |
- if (candidate.rfind("_GRP") == evt_name_len) {
|
|
|
d5df0a |
- event_found = true;
|
|
|
d5df0a |
- break;
|
|
|
d5df0a |
- } else {
|
|
|
d5df0a |
- memset(event_name, '\0', OP_MAX_EVT_NAME_LEN);
|
|
|
d5df0a |
- strncpy(event_name, save_event_name.c_str(), evt_name_len);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- pclose(fp);
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-out:
|
|
|
d5df0a |
- if (!event_found) {
|
|
|
d5df0a |
- cerr << err_msg << event_name << endl;
|
|
|
d5df0a |
- cerr << "Error retrieving info for event "
|
|
|
d5df0a |
- << event_spec << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- retval = event_name;
|
|
|
d5df0a |
- return retval + ":" + count_str;
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-#endif
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-static void _process_events_list(void)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
- string cmd = OP_BINDIR;
|
|
|
d5df0a |
- if (operf_options::evts.size() > OP_MAX_EVENTS) {
|
|
|
d5df0a |
- cerr << "Number of events specified is greater than allowed maximum of "
|
|
|
d5df0a |
- << OP_MAX_EVENTS << "." << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- cmd += "/ophelp --check-events ";
|
|
|
d5df0a |
- for (unsigned int i = 0; i < operf_options::evts.size(); i++) {
|
|
|
d5df0a |
- FILE * fp;
|
|
|
d5df0a |
- string full_cmd = cmd;
|
|
|
d5df0a |
- string event_spec = operf_options::evts[i];
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-#if PPC64_ARCH
|
|
|
d5df0a |
- // Starting with CPU_PPC64_ARCH_V1, ppc64 events files are formatted like
|
|
|
d5df0a |
- // other architectures, so no special handling is needed.
|
|
|
d5df0a |
- if (cpu_type < CPU_PPC64_ARCH_V1)
|
|
|
d5df0a |
- event_spec = _handle_powerpc_event_spec(event_spec);
|
|
|
d5df0a |
-#endif
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- if (operf_options::callgraph) {
|
|
|
d5df0a |
- full_cmd += " --callgraph=1 ";
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- full_cmd += event_spec;
|
|
|
d5df0a |
- fp = popen(full_cmd.c_str(), "r");
|
|
|
d5df0a |
- if (fp == NULL) {
|
|
|
d5df0a |
- cerr << "Unable to execute ophelp to get info for event "
|
|
|
d5df0a |
- << event_spec << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- if (fgetc(fp) == EOF) {
|
|
|
d5df0a |
- pclose(fp);
|
|
|
d5df0a |
- cerr << "Error retrieving info for event "
|
|
|
d5df0a |
- << event_spec << endl;
|
|
|
d5df0a |
- if (operf_options::callgraph)
|
|
|
d5df0a |
- cerr << "Note: When doing callgraph profiling, the sample count must be"
|
|
|
d5df0a |
- << endl << "15 times the minimum count value for the event." << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- pclose(fp);
|
|
|
d5df0a |
- char * event_str = op_xstrndup(event_spec.c_str(), event_spec.length());
|
|
|
d5df0a |
- operf_event_t event;
|
|
|
d5df0a |
- strncpy(event.name, strtok(event_str, ":"), OP_MAX_EVT_NAME_LEN - 1);
|
|
|
d5df0a |
- event.count = atoi(strtok(NULL, ":"));
|
|
|
d5df0a |
- /* Name and count are required in the event spec in order for
|
|
|
d5df0a |
- * 'ophelp --check-events' to pass. But since unit mask and domain
|
|
|
d5df0a |
- * control bits are optional, we need to ensure the result of strtok
|
|
|
d5df0a |
- * is valid.
|
|
|
d5df0a |
- */
|
|
|
d5df0a |
- char * info;
|
|
|
d5df0a |
-#define _OP_UM 1
|
|
|
d5df0a |
-#define _OP_KERNEL 2
|
|
|
d5df0a |
-#define _OP_USER 3
|
|
|
d5df0a |
- int place = _OP_UM;
|
|
|
d5df0a |
- char * endptr = NULL;
|
|
|
d5df0a |
- event.evt_um = 0ULL;
|
|
|
d5df0a |
- event.no_kernel = 0;
|
|
|
d5df0a |
- event.no_user = 0;
|
|
|
d5df0a |
- event.throttled = false;
|
|
|
d5df0a |
- memset(event.um_name, '\0', OP_MAX_UM_NAME_LEN);
|
|
|
d5df0a |
- while ((info = strtok(NULL, ":"))) {
|
|
|
d5df0a |
- switch (place) {
|
|
|
d5df0a |
- case _OP_UM:
|
|
|
d5df0a |
- event.evt_um = strtoul(info, &endptr, 0);
|
|
|
d5df0a |
- // If any of the UM part is not a number, then we
|
|
|
d5df0a |
- // consider the entire part a string.
|
|
|
d5df0a |
- if (*endptr) {
|
|
|
d5df0a |
- event.evt_um = 0;
|
|
|
d5df0a |
- strncpy(event.um_name, info, OP_MAX_UM_NAME_LEN - 1);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- break;
|
|
|
d5df0a |
- case _OP_KERNEL:
|
|
|
d5df0a |
- if (atoi(info) == 0)
|
|
|
d5df0a |
- event.no_kernel = 1;
|
|
|
d5df0a |
- break;
|
|
|
d5df0a |
- case _OP_USER:
|
|
|
d5df0a |
- if (atoi(info) == 0)
|
|
|
d5df0a |
- event.no_user = 1;
|
|
|
d5df0a |
- break;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- place++;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- free(event_str);
|
|
|
d5df0a |
- _get_event_code(&event);
|
|
|
d5df0a |
- events.push_back(event);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-#if PPC64_ARCH
|
|
|
d5df0a |
- {
|
|
|
d5df0a |
- /* For ppc64 architecture processors prior to the introduction of
|
|
|
d5df0a |
- * architected_events_v1, the oprofile event code needs to be converted
|
|
|
d5df0a |
- * to the appropriate event code to pass to the perf_event_open syscall.
|
|
|
d5df0a |
- * But as of the introduction of architected_events_v1, the events
|
|
|
d5df0a |
- * file contains the necessary event code information, so this conversion
|
|
|
d5df0a |
- * step is no longer needed.
|
|
|
d5df0a |
- */
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- using namespace OP_perf_utils;
|
|
|
d5df0a |
- if ((cpu_type < CPU_PPC64_ARCH_V1) && !op_convert_event_vals(&events)) {
|
|
|
d5df0a |
- cerr << "Unable to convert all oprofile event values to perf_event values" << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-#endif
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-static void get_default_event(void)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
- operf_event_t dft_evt;
|
|
|
d5df0a |
- struct op_default_event_descr descr;
|
|
|
d5df0a |
- vector<operf_event_t> tmp_events;
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- op_default_event(cpu_type, &descr);
|
|
|
d5df0a |
- if (descr.name[0] == '\0') {
|
|
|
d5df0a |
- cerr << "Unable to find default event" << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- memset(&dft_evt, 0, sizeof(dft_evt));
|
|
|
d5df0a |
- if (operf_options::callgraph) {
|
|
|
d5df0a |
- struct op_event * _event;
|
|
|
d5df0a |
- op_events(cpu_type);
|
|
|
d5df0a |
- if ((_event = find_event_by_name(descr.name, 0, 0))) {
|
|
|
d5df0a |
- dft_evt.count = _event->min_count * CALLGRAPH_MIN_COUNT_SCALE;
|
|
|
d5df0a |
- } else {
|
|
|
d5df0a |
- cerr << "Error getting event info for " << descr.name << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- } else {
|
|
|
d5df0a |
- dft_evt.count = descr.count;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- dft_evt.evt_um = descr.um;
|
|
|
d5df0a |
- strncpy(dft_evt.name, descr.name, OP_MAX_EVT_NAME_LEN - 1);
|
|
|
d5df0a |
- _get_event_code(&dft_evt);
|
|
|
d5df0a |
- events.push_back(dft_evt);
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-#if PPC64_ARCH
|
|
|
d5df0a |
- {
|
|
|
d5df0a |
- /* This section of code is for architectures such as ppc[64] for which
|
|
|
d5df0a |
- * the oprofile event code needs to be converted to the appropriate event
|
|
|
d5df0a |
- * code to pass to the perf_event_open syscall.
|
|
|
d5df0a |
- */
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- using namespace OP_perf_utils;
|
|
|
d5df0a |
- if ((cpu_type < CPU_PPC64_ARCH_V1) && !op_convert_event_vals(&events)) {
|
|
|
d5df0a |
- cerr << "Unable to convert all oprofile event values to perf_event values" << endl;
|
|
|
d5df0a |
- exit(EXIT_FAILURE);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-#endif
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-
|
|
|
d5df0a |
static void _process_session_dir(void)
|
|
|
d5df0a |
{
|
|
|
d5df0a |
if (operf_options::session_dir.empty()) {
|
|
|
d5df0a |
@@ -1752,7 +1242,7 @@ static void process_args(int argc, char * const argv[])
|
|
|
d5df0a |
app_args = (char **) xmalloc((sizeof *app_args) * 2);
|
|
|
d5df0a |
app_args[1] = NULL;
|
|
|
d5df0a |
}
|
|
|
d5df0a |
- if (validate_app_name() < 0) {
|
|
|
d5df0a |
+ if (op_validate_app_name(&app_name, &app_name_SAVE) < 0) {
|
|
|
d5df0a |
__print_usage_and_exit(NULL);
|
|
|
d5df0a |
}
|
|
|
d5df0a |
} else { // non_options_idx == 0
|
|
|
d5df0a |
@@ -1783,9 +1273,9 @@ static void process_args(int argc, char * const argv[])
|
|
|
d5df0a |
|
|
|
d5df0a |
if (operf_options::evts.empty()) {
|
|
|
d5df0a |
// Use default event
|
|
|
d5df0a |
- get_default_event();
|
|
|
d5df0a |
+ op_get_default_event(operf_options::callgraph);
|
|
|
d5df0a |
} else {
|
|
|
d5df0a |
- _process_events_list();
|
|
|
d5df0a |
+ op_process_events_list(operf_options::evts, true, operf_options::callgraph);
|
|
|
d5df0a |
}
|
|
|
d5df0a |
op_nr_events = events.size();
|
|
|
d5df0a |
|
|
|
d5df0a |
@@ -1800,87 +1290,6 @@ static void process_args(int argc, char * const argv[])
|
|
|
d5df0a |
return;
|
|
|
d5df0a |
}
|
|
|
d5df0a |
|
|
|
d5df0a |
-static int _get_cpu_for_perf_events_cap(void)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
- int retval;
|
|
|
d5df0a |
- string err_msg;
|
|
|
d5df0a |
- char cpus_online[257];
|
|
|
d5df0a |
- FILE * online_cpus;
|
|
|
d5df0a |
- DIR *dir = NULL;
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- int total_cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
|
|
d5df0a |
- if (!total_cpus) {
|
|
|
d5df0a |
- err_msg = "Internal Error (1): Number of online cpus cannot be determined.";
|
|
|
d5df0a |
- retval = -1;
|
|
|
d5df0a |
- goto error;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- online_cpus = fopen("/sys/devices/system/cpu/online", "r");
|
|
|
d5df0a |
- if (!online_cpus) {
|
|
|
d5df0a |
- err_msg = "Internal Error (2): Number of online cpus cannot be determined.";
|
|
|
d5df0a |
- retval = -1;
|
|
|
d5df0a |
- goto error;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- memset(cpus_online, 0, sizeof(cpus_online));
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- if ( fgets(cpus_online, sizeof(cpus_online), online_cpus) == NULL) {
|
|
|
d5df0a |
- fclose(online_cpus);
|
|
|
d5df0a |
- err_msg = "Internal Error (3): Number of online cpus cannot be determined.";
|
|
|
d5df0a |
- retval = -1;
|
|
|
d5df0a |
- goto error;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- if (!cpus_online[0]) {
|
|
|
d5df0a |
- fclose(online_cpus);
|
|
|
d5df0a |
- err_msg = "Internal Error (4): Number of online cpus cannot be determined.";
|
|
|
d5df0a |
- retval = -1;
|
|
|
d5df0a |
- goto error;
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- if (index(cpus_online, ',') || cpus_online[0] != '0') {
|
|
|
d5df0a |
- // A comma in cpus_online implies a gap, which in turn implies that not all
|
|
|
d5df0a |
- // CPUs are online.
|
|
|
d5df0a |
- if ((dir = opendir("/sys/devices/system/cpu")) == NULL) {
|
|
|
d5df0a |
- fclose(online_cpus);
|
|
|
d5df0a |
- err_msg = "Internal Error (5): Number of online cpus cannot be determined.";
|
|
|
d5df0a |
- retval = -1;
|
|
|
d5df0a |
- goto error;
|
|
|
d5df0a |
- } else {
|
|
|
d5df0a |
- struct dirent *entry = NULL;
|
|
|
d5df0a |
- retval = OP_perf_utils::op_get_next_online_cpu(dir, entry);
|
|
|
d5df0a |
- closedir(dir);
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- } else {
|
|
|
d5df0a |
- // All CPUs are available, so we just arbitrarily choose CPU 0.
|
|
|
d5df0a |
- retval = 0;
|
|
|
d5df0a |
- }
|
|
|
d5df0a |
- fclose(online_cpus);
|
|
|
d5df0a |
-error:
|
|
|
d5df0a |
- return retval;
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-static int _check_perf_events_cap(bool use_cpu_minus_one)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
- /* If perf_events syscall is not implemented, the syscall below will fail
|
|
|
d5df0a |
- * with ENOSYS (38). If implemented, but the processor type on which this
|
|
|
d5df0a |
- * program is running is not supported by perf_events, the syscall returns
|
|
|
d5df0a |
- * ENOENT (2).
|
|
|
d5df0a |
- */
|
|
|
d5df0a |
- struct perf_event_attr attr;
|
|
|
d5df0a |
- pid_t pid ;
|
|
|
d5df0a |
- int cpu_to_try = use_cpu_minus_one ? -1 : _get_cpu_for_perf_events_cap();
|
|
|
d5df0a |
- errno = 0;
|
|
|
d5df0a |
- memset(&attr, 0, sizeof(attr));
|
|
|
d5df0a |
- attr.size = sizeof(attr);
|
|
|
d5df0a |
- attr.sample_type = PERF_SAMPLE_IP;
|
|
|
d5df0a |
-
|
|
|
d5df0a |
- pid = getpid();
|
|
|
d5df0a |
- syscall(__NR_perf_event_open, &attr, pid, cpu_to_try, -1, 0);
|
|
|
d5df0a |
- return errno;
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-
|
|
|
d5df0a |
static void _precheck_permissions_to_samplesdir(string sampledir, bool for_current)
|
|
|
d5df0a |
{
|
|
|
d5df0a |
/* Pre-check to make sure we have permission to remove old sample data
|
|
|
d5df0a |
@@ -1911,28 +1320,14 @@ static void _precheck_permissions_to_samplesdir(string sampledir, bool for_curre
|
|
|
d5df0a |
|
|
|
d5df0a |
}
|
|
|
d5df0a |
|
|
|
d5df0a |
-static int _get_sys_value(const char * filename)
|
|
|
d5df0a |
-{
|
|
|
d5df0a |
- char str[10];
|
|
|
d5df0a |
- int _val = -999;
|
|
|
d5df0a |
- FILE * fp = fopen(filename, "r");
|
|
|
d5df0a |
- if (fp == NULL)
|
|
|
d5df0a |
- return _val;
|
|
|
d5df0a |
- if (fgets(str, 9, fp))
|
|
|
d5df0a |
- sscanf(str, "%d", &_val);
|
|
|
d5df0a |
- fclose(fp);
|
|
|
d5df0a |
- return _val;
|
|
|
d5df0a |
-}
|
|
|
d5df0a |
-
|
|
|
d5df0a |
-
|
|
|
d5df0a |
int main(int argc, char * const argv[])
|
|
|
d5df0a |
{
|
|
|
d5df0a |
int rc;
|
|
|
d5df0a |
- int perf_event_paranoid = _get_sys_value("/proc/sys/kernel/perf_event_paranoid");
|
|
|
d5df0a |
+ int perf_event_paranoid = op_get_sys_value("/proc/sys/kernel/perf_event_paranoid");
|
|
|
d5df0a |
|
|
|
d5df0a |
my_uid = geteuid();
|
|
|
d5df0a |
throttled = false;
|
|
|
d5df0a |
- rc = _check_perf_events_cap(use_cpu_minus_one);
|
|
|
d5df0a |
+ rc = op_check_perf_events_cap(use_cpu_minus_one);
|
|
|
d5df0a |
if (rc == EACCES) {
|
|
|
d5df0a |
/* Early perf_events kernels required the cpu argument to perf_event_open
|
|
|
d5df0a |
* to be '-1' when setting up to profile a single process if 1) the user is
|
|
|
d5df0a |
@@ -1948,7 +1343,7 @@ int main(int argc, char * const argv[])
|
|
|
d5df0a |
*/
|
|
|
d5df0a |
if (my_uid != 0 && perf_event_paranoid > 0) {
|
|
|
d5df0a |
use_cpu_minus_one = true;
|
|
|
d5df0a |
- rc = _check_perf_events_cap(use_cpu_minus_one);
|
|
|
d5df0a |
+ rc = op_check_perf_events_cap(use_cpu_minus_one);
|
|
|
d5df0a |
}
|
|
|
d5df0a |
}
|
|
|
d5df0a |
if (rc == EBUSY) {
|
|
|
d5df0a |
@@ -1996,7 +1391,7 @@ int main(int argc, char * const argv[])
|
|
|
d5df0a |
_precheck_permissions_to_samplesdir(previous_sampledir, for_current);
|
|
|
d5df0a |
}
|
|
|
d5df0a |
}
|
|
|
d5df0a |
- kptr_restrict = _get_sys_value("/proc/sys/kernel/kptr_restrict");
|
|
|
d5df0a |
+ kptr_restrict = op_get_sys_value("/proc/sys/kernel/kptr_restrict");
|
|
|
d5df0a |
end_code_t run_result;
|
|
|
d5df0a |
if ((run_result = _run())) {
|
|
|
d5df0a |
if (startApp && app_started && (run_result != APP_ABNORMAL_END)) {
|