aboutsummaryrefslogtreecommitdiff
path: root/gprofng/src/collctrl.cc
diff options
context:
space:
mode:
authorVladimir Mezentsev <vladimir.mezentsev@oracle.com>2024-01-08 22:00:24 -0800
committerVladimir Mezentsev <vladimir.mezentsev@oracle.com>2024-01-10 09:31:08 -0800
commit8fe04eeb2cbb8c4cf7b6e8d9183fe09a8b2e8d51 (patch)
treec3c29dfecf57ea78d8de663665a8c4ab53706b6a /gprofng/src/collctrl.cc
parente1cab50d2dd3d416662b5399bd80e6311a6ade0e (diff)
downloadbinutils-8fe04eeb2cbb8c4cf7b6e8d9183fe09a8b2e8d51.zip
binutils-8fe04eeb2cbb8c4cf7b6e8d9183fe09a8b2e8d51.tar.gz
binutils-8fe04eeb2cbb8c4cf7b6e8d9183fe09a8b2e8d51.tar.bz2
gprofng: 31123 improvements to hardware event implementation
Our hardware counter profiling is based on perf_event_open(). Our HWC tables are absent for new machines. I have added HWC tables for the following events: PERF_TYPE_HARDWARE, PERF_TYPE_SOFTWARE, PERF_TYPE_HW_CACHE. Other events require additional fixes. Did a little cleaning: marked the symbols as static, used Stringbuilder, created a function to read /proc/cpuinfo. gprofng/ChangeLog 2024-01-08 Vladimir Mezentsev <vladimir.mezentsev@oracle.com> PR gprofng/31123 * common/core_pcbe.c: Mark the symbols as static. Add events_generic[]. * common/hwc_cpus.h: Declare a new function read_cpuinfo. * common/hwcdrv.c: Add a new parameter in init_perf_event(). * common/hwcentry.h: Add use_perf_event_type in Hwcentry. * common/hwcfuncs.c (process_data_descriptor): Read use_perf_event_type, type, config. * common/hwctable.c: Add a new HWC table generic_list[]. * common/opteron_pcbe.c (opt_pcbe_init): Accept AMD machines. * src/collctrl.cc: Use StringBuilder in Coll_Ctrl::build_data_desc(). Add a new function read_cpuinfo.
Diffstat (limited to 'gprofng/src/collctrl.cc')
-rw-r--r--gprofng/src/collctrl.cc211
1 files changed, 111 insertions, 100 deletions
diff --git a/gprofng/src/collctrl.cc b/gprofng/src/collctrl.cc
index 703344c..ebf888c 100644
--- a/gprofng/src/collctrl.cc
+++ b/gprofng/src/collctrl.cc
@@ -39,7 +39,7 @@
#include "libiberty.h"
#include "collctrl.h"
#include "hwcdrv.h"
-//#include "hwcfuncs.h"
+#include "StringBuilder.h"
#define SP_GROUP_HEADER "#analyzer experiment group"
#define DD_MAXPATHLEN (MAXPATHLEN * 4) /* large, to build up data descriptor */
@@ -55,7 +55,84 @@ extern const char *strsignal (int);
#define _SC_CPUID_MAX 517
#endif
-const char *get_fstype (char *);
+static const char *get_fstype (char *);
+static cpu_info_t cpu_info;
+
+static void
+read_str (char *from, char **to)
+{
+ if (*to != NULL)
+ return;
+ for (char *s = from; *s; s++)
+ if (*s != ':' && *s != '\t' && *s != ' ')
+ {
+ for (int i = ((int) strlen (s)) - 1; i >= 0; i--)
+ {
+ if (s[i] != '\n' && s[i] != ' ' && s[i] != '\t')
+ {
+ *to = strndup(s, i + 1);
+ return;
+ }
+ }
+ return; // string is empty
+ }
+}
+
+static int
+read_int (char *from)
+{
+ char *val = strchr (from, ':');
+ if (val)
+ return atoi (val + 1);
+ return 0;
+}
+
+cpu_info_t *
+read_cpuinfo()
+{
+ static int inited = 0;
+ if (inited)
+ return &cpu_info;
+ inited = 1;
+
+#if defined(__aarch64__)
+ asm volatile("mrs %0, cntfrq_el0" : "=r" (cpu_info.cpu_clk_freq));
+#endif
+
+ // Read /proc/cpuinfo to get CPU info and clock rate
+ FILE *procf = fopen ("/proc/cpuinfo", "r");
+ if (procf != NULL)
+ {
+ char temp[1024];
+ while (fgets (temp, (int) sizeof (temp), procf) != NULL)
+ {
+ if (strncmp (temp, "processor", 9) == 0)
+ cpu_info.cpu_cnt++;
+ else if (strncmp (temp, "cpu MHz", 7) == 0)
+ cpu_info.cpu_clk_freq = read_int (temp + 9);
+ else if (strncmp (temp, "cpu family", 10) == 0)
+ cpu_info.cpu_family = read_int (temp + 10);
+ else if (strncmp (temp, "vendor_id", 9) == 0)
+ {
+ if (cpu_info.cpu_vendorstr == NULL)
+ read_str (temp + 9, &cpu_info.cpu_vendorstr);
+ }
+ else if (strncmp (temp, "model name", 10) == 0)
+ {
+ if (cpu_info.cpu_modelstr == NULL)
+ read_str (temp + 10, &cpu_info.cpu_modelstr);
+ }
+ else if (strncmp (temp, "model", 5) == 0)
+ cpu_info.cpu_model = read_int (temp + 5);
+ else if (strncmp (temp, "CPU implementer", 15) == 0)
+ cpu_info.cpu_family = read_int (temp + 15);
+ else if (strncmp (temp, "CPU architecture", 16) == 0)
+ cpu_info.cpu_model = read_int (temp + 16);
+ }
+ fclose (procf);
+ }
+ return &cpu_info;
+}
Coll_Ctrl::Coll_Ctrl (int _interactive, bool _defHWC, bool _kernelHWC)
{
@@ -81,59 +158,9 @@ Coll_Ctrl::Coll_Ctrl (int _interactive, bool _defHWC, bool _kernelHWC)
/* add 2048 to count, since on some systems CPUID does not start at zero */
ncpumax = ncpus + 2048;
}
- ncpus = 0;
- cpu_clk_freq = 0;
-
- // On Linux, read /proc/cpuinfo to get CPU count and clock rate
- // Note that parsing is different on SPARC and x86
-#if defined(sparc)
- FILE *procf = fopen ("/proc/cpuinfo", "r");
- if (procf != NULL)
- {
- char temp[1024];
- while (fgets (temp, (int) sizeof (temp), procf) != NULL)
- {
- if (strncmp (temp, "Cpu", 3) == 0 && temp[3] != '\0'
- && strncmp ((strchr (temp + 1, 'C')) ? strchr (temp + 1, 'C')
- : (temp + 4), "ClkTck", 6) == 0)
- {
- ncpus++;
- char *val = strchr (temp, ':');
- if (val)
- {
- unsigned long long freq;
- sscanf (val + 2, "%llx", &freq);
- cpu_clk_freq = (unsigned int) (((double) freq) / 1000000.0 + 0.5);
- }
- else
- cpu_clk_freq = 0;
- }
- }
- fclose (procf);
- }
-
-#elif defined(__aarch64__)
- asm volatile("mrs %0, cntfrq_el0" : "=r" (cpu_clk_freq));
-
-#else
- FILE *procf = fopen ("/proc/cpuinfo", "r");
- if (procf != NULL)
- {
- char temp[1024];
- while (fgets (temp, (int) sizeof (temp), procf) != NULL)
- {
- // x86 Linux
- if (strncmp (temp, "processor", 9) == 0)
- ncpus++;
- else if (strncmp (temp, "cpu MHz", 7) == 0)
- {
- char *val = strchr (temp, ':');
- cpu_clk_freq = val ? atoi (val + 1) : 0;
- }
- }
- fclose (procf);
- }
-#endif
+ cpu_info_t *cpu_p = read_cpuinfo();
+ ncpus = cpu_p->cpu_cnt;
+ cpu_clk_freq = cpu_p->cpu_clk_freq;
/* check resolution of system clock */
sys_resolution = sysconf (_SC_CLK_TCK);
@@ -1720,78 +1747,62 @@ Coll_Ctrl::set_size_limit (const char *string)
void
Coll_Ctrl::build_data_desc ()
{
- char spec[DD_MAXPATHLEN];
- spec[0] = 0;
+ StringBuilder sb;
// Put sample sig before clock profiling. Dbx uses PROF
// for that purpose and we want it to be processed first.
if (project_home)
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "P:%s;", project_home);
+ sb.appendf ("P:%s;", project_home);
if (sample_sig != 0)
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "g:%d;", sample_sig);
+ sb.appendf ("g:%d;", sample_sig);
if (pauseresume_sig != 0)
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "d:%d%s;", pauseresume_sig,
- (pauseresume_pause == 1 ? "p" : ""));
+ sb.appendf ("d:%d%s;", pauseresume_sig, pauseresume_pause == 1 ? "p" : "");
if (clkprof_enabled == 1)
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "p:%d;", clkprof_timer);
+ sb.appendf ("p:%d;", clkprof_timer);
if (synctrace_enabled == 1)
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "s:%d,%d;", synctrace_thresh, synctrace_scope);
+ sb.appendf ("s:%d,%d;", synctrace_thresh, synctrace_scope);
if (heaptrace_enabled == 1)
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "H:%d;", heaptrace_checkenabled);
+ sb.appendf ("H:%d;", heaptrace_checkenabled);
if (iotrace_enabled == 1)
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "i:;");
+ sb.append ("i:;");
if (hwcprof_enabled_cnt > 0)
{
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "h:%s",
- (hwcprof_default == true) ? "*" : "");
+ sb.appendf ("h:%s", (hwcprof_default == true) ? "*" : "");
for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
{
- /* min_time is a "new" field.
- *
- * To help process_data_descriptor() in hwcfuncs.c parse
- * the HWC portion of this string -- specifically, to
- * recognize min_time when it's present and skip over
- * when it's not -- we prepend 'm' to the min_time value.
- *
- * When we no longer worry about, say, an old dbx
- * writing this string and a new libcollector looking for
- * the min_time field, the 'm' character can be
- * removed and process_data_descriptor() simplified.
- */
- hrtime_t min_time = hwctr[ii].min_time;
+ Hwcentry *h = hwctr + ii;
+ hrtime_t min_time = h->min_time;
if (min_time == HWCTIME_TBD)
// user did not specify any value for overflow rate
- min_time = hwctr[ii].min_time_default;
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec),
- "%s%s:%s:%d:%d:m%lld:%d:%d:0x%x", ii ? "," : "",
- strcmp (hwctr[ii].name, hwctr[ii].int_name) ? hwctr[ii].name : "",
- hwctr[ii].int_name, hwctr[ii].reg_num, hwctr[ii].val,
- min_time, ii, /*tag*/ hwctr[ii].timecvt, hwctr[ii].memop);
+ min_time = h->min_time_default;
+ if (ii > 0)
+ sb.append (',');
+ sb.appendf ("%d:%d:%lld:%s:%s:%lld:%d:m%lld:%d:%d:0x%x",
+ h->use_perf_event_type, h->type, (long long) h->config,
+ strcmp (h->name, h->int_name) ? h->name : "",
+ h->int_name, (long long) h->reg_num, h->val,
+ (long long) min_time, ii, /*tag*/ h->timecvt, h->memop);
}
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), ";");
+ sb.append (";");
}
- if ((time_run != 0) || (start_delay != 0))
+ if (time_run != 0 || start_delay != 0)
{
if (start_delay != 0)
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "t:%d:%d;", start_delay, time_run);
+ sb.appendf ("t:%d:%d;", start_delay, time_run);
else
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "t:%d;", time_run);
+ sb.appendf ("t:%d;", time_run);
}
if (sample_period != 0)
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "S:%d;",
- sample_period);
+ sb.appendf ("S:%d;", sample_period);
if (size_limit != 0)
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "L:%d;",
- size_limit);
+ sb.appendf ("L:%d;", size_limit);
if (java_mode != 0)
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "j:%d;", (int) java_mode);
+ sb.appendf ("j:%d;", (int) java_mode);
if (follow_mode != FOLLOW_NONE)
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "F:%d;", (int) follow_mode);
- snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "a:%s;", archive_mode);
- if (strlen (spec) + 1 >= sizeof (spec))
- abort ();
+ sb.appendf ("F:%d;", (int) follow_mode);
+ sb.appendf ("a:%s;", archive_mode);
free (data_desc);
- data_desc = strdup (spec);
+ data_desc = sb.toString ();
}
char *