Read the scale and unit values from the
sysfs 
(/sys/bus/event_source/devices/uncore_imc_*/events/cas_count_{read,write}.scale)
for intel sandy-bridge uncore memory controllers' read and write
counters. These values are needed to scale the counter values.

This patch also adds a function pfm_get_os_event_scale() to the libpfm
API so that tools using perfmon/libpfm4 library can get the value of the
scale similar to how pfm_get_os_event_encoding() gets the event
encoding.

Signed-off-by: Hemant Kumar <hem...@linux.vnet.ibm.com>
---
 include/perfmon/pfmlib.h |  6 ++++
 lib/pfmlib_common.c      | 31 ++++++++++++++++++++
 lib/pfmlib_intel_x86.c   | 25 ++++++++++++++++
 lib/pfmlib_perf_event.c  | 75 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/pfmlib_priv.h        |  1 +
 5 files changed, 138 insertions(+)

diff --git a/include/perfmon/pfmlib.h b/include/perfmon/pfmlib.h
index 2fb4744..543a8b2 100644
--- a/include/perfmon/pfmlib.h
+++ b/include/perfmon/pfmlib.h
@@ -412,6 +412,7 @@ typedef struct {
        const char              *name;  /* attribute symbolic name */
        const char              *desc;  /* attribute description */
        const char              *equiv; /* attribute is equivalent to */
+       const char              *uname;
        size_t                  size;   /* struct sizeof */
        uint64_t                code;   /* attribute code */
        pfm_attr_t              type;   /* attribute type */
@@ -484,6 +485,11 @@ extern pfm_err_t pfm_get_event_info(int idx, pfm_os_t os, 
pfm_event_info_t *outp
 extern pfm_err_t pfm_get_os_event_encoding(const char *str, int dfl_plm, 
pfm_os_t os, void *args);
 
 /*
+ * event scale API
+ */
+extern pfm_err_t pfm_get_os_event_scale(const char *str, int dfl_plm, pfm_os_t 
os, void *args);
+
+/*
  * attribute API
  */
 extern pfm_err_t pfm_get_event_attr_info(int eidx, int aidx, pfm_os_t os, 
pfm_event_attr_info_t *output);
diff --git a/lib/pfmlib_common.c b/lib/pfmlib_common.c
index a6a364e..a108ada 100644
--- a/lib/pfmlib_common.c
+++ b/lib/pfmlib_common.c
@@ -1350,10 +1350,34 @@ pfm_get_event_next(int idx)
 }
 
 int
+pfm_get_os_event_scale(const char *str, int dfl_plm, pfm_os_t uos, void *args)
+{
+       pfmlib_os_t *os;
+
+       if (PFMLIB_INITIALIZED() == 0)
+               return PFM_ERR_NOINIT;
+
+       if (dfl_plm & ~(PFM_PLM_ALL))
+               return PFM_ERR_INVAL;
+
+       os = pfmlib_find_os(uos);
+       if (!os)
+               return PFM_ERR_NOTSUPP;
+
+       return os->get_scale(os, str, dfl_plm, args);
+}
+
+int
 pfm_get_os_event_encoding(const char *str, int dfl_plm, pfm_os_t uos, void 
*args)
 {
        pfmlib_os_t *os;
 
+       FILE *fp;
+
+       fp = fopen("/home/hemant/tmp.txt", "w");
+       if (!fp)
+               return PFM_ERR_NOINIT;
+       fprintf(fp, "os->name : %s\n", os->name);
        if (PFMLIB_INITIALIZED() == 0)
                return PFM_ERR_NOINIT;
 
@@ -1981,10 +2005,17 @@ pfmlib_raw_pmu_detect(void *this)
        return PFM_SUCCESS;
 }
 
+static int
+pfmlib_raw_pmu_get_scale(void *this, const char *str, int dfl_plm, void *data)
+{
+       return PFM_ERR_NOTSUPP;
+}
+
 static pfmlib_os_t pfmlib_os_none= {
        .name = "No OS (raw PMU)",
        .id = PFM_OS_NONE,
        .flags = PFMLIB_OS_FL_ACTIVATED,
        .encode = pfmlib_raw_pmu_encode,
        .detect = pfmlib_raw_pmu_detect,
+       .get_scale = pfmlib_raw_pmu_get_scale,
 };
diff --git a/lib/pfmlib_intel_x86.c b/lib/pfmlib_intel_x86.c
index 81a2258..cb76cd1 100644
--- a/lib/pfmlib_intel_x86.c
+++ b/lib/pfmlib_intel_x86.c
@@ -894,6 +894,30 @@ skip_dfl:
        return error ? PFM_ERR_INVAL : PFM_SUCCESS;
 }
 
+#define MAX_LEN 100
+
+static char *
+get_attr_uname(void *this, int pidx, int idx)
+{
+       const intel_x86_entry_t *pe = this_pe(this);
+       char *text = NULL;
+
+       if (!strcmp(pe[pidx].name, "UNC_M_CAS_COUNT")) {
+               text = calloc(MAX_LEN, sizeof(char));
+               if (!text)
+                       return NULL;
+               strcpy(text, "cas_count_");
+       }
+       if (text) {
+               if (!strcmp(pe[pidx].umasks[idx].uname, "RD"))
+                       strcat(text, "read");
+               else if(!strcmp(pe[pidx].umasks[idx].uname, "WR"))
+                       strcat(text, "write");
+       }
+
+       return text;
+}
+
 int
 pfm_intel_x86_get_event_attr_info(void *this, int pidx, int attr_idx, 
pfm_event_attr_info_t *info)
 {
@@ -906,6 +930,7 @@ pfm_intel_x86_get_event_attr_info(void *this, int pidx, int 
attr_idx, pfm_event_
                idx = intel_x86_attr2umask(this, pidx, attr_idx);
                info->name = pe[pidx].umasks[idx].uname;
                info->desc = pe[pidx].umasks[idx].udesc;
+               info->uname = get_attr_uname(this, pidx, idx);
                info->equiv= pe[pidx].umasks[idx].uequiv;
 
                info->code = pe[pidx].umasks[idx].ucode;
diff --git a/lib/pfmlib_perf_event.c b/lib/pfmlib_perf_event.c
index 8618d60..7f191f0 100644
--- a/lib/pfmlib_perf_event.c
+++ b/lib/pfmlib_perf_event.c
@@ -73,6 +73,79 @@ static const pfmlib_attr_desc_t perf_event_ext_mods[]={
        PFM_ATTR_NULL /* end-marker to avoid exporting number of entries */
 };
 
+static double
+get_perf_scale(const char *pmu, const char *event)
+{
+       char scale_path[PATH_MAX];
+
+       FILE *fp;
+       size_t len = 0;
+       char *line = NULL;
+       ssize_t ret;
+       double scale;
+
+       sprintf(scale_path, "/sys/bus/event_source/devices/%s/events/%s.scale",
+               pmu, event);
+
+       fp = fopen(scale_path, "r");
+       if (!fp)
+               goto end;
+
+       ret = getline(&line, &len, fp);
+       if (ret > 0) {
+               /* Remove the new line from the end of the string here */
+               if (line[strlen(line) - 1]  == '\n')
+                       line[strlen(line) - 1] = '\0';
+
+               scale = atof(line);
+               free(line);
+               fclose(fp);
+               return scale;
+       }
+       if (fp)
+               fclose(fp);
+end:
+       return 1.0;
+}
+
+static int
+pfmlib_perf_event_scale(void *this, const char *str, int dfl_plm, void *data)
+{
+       pfmlib_os_t *os = this;
+       pfmlib_pmu_t *pmu;
+       pfmlib_event_desc_t e;
+       pfm_event_attr_info_t ainfo;
+       int ret;
+       double *scale = data;
+
+       memset(&e, 0, sizeof(e));
+
+       e.osid = os->id;
+       e.dfl_plm = dfl_plm;
+
+       /* after this call, need to call pfmlib_release_event() */
+       ret = pfmlib_parse_event(str, &e);
+       if (ret != PFM_SUCCESS)
+               return ret;
+
+       pmu = e.pmu;
+
+       fprintf(stderr, "event name : %s\n", str);
+       fprintf(stderr, "PMU name : %s\n", (e.pmu)->perf_name);
+       fprintf(stderr, "attribute name : %d\n", (e.attrs)->id);
+
+       /* need to free up ainfo.uname */
+       ret = pmu->get_event_attr_info(pmu, e.event, (e.attrs)->id, &ainfo);
+       if (ainfo.uname) {
+               fprintf(stderr, "UNAME : %s\n", ainfo.uname);
+               *scale = get_perf_scale((e.pmu)->perf_name, ainfo.uname);
+               fprintf(stderr, "scale : %f\n", *scale);
+       }
+
+       pfmlib_release_event(&e);
+       return ret;
+}
+
 static int
 pfmlib_perf_event_encode(void *this, const char *str, int dfl_plm, void *data)
 {
@@ -432,6 +505,7 @@ pfmlib_os_t pfmlib_os_perf={
        .get_os_attr_info = perf_get_os_attr_info,
        .get_os_nattrs = perf_get_os_nattrs,
        .encode = pfmlib_perf_event_encode,
+       .get_scale = pfmlib_perf_event_scale,
 };
 
 pfmlib_os_t pfmlib_os_perf_ext={
@@ -442,6 +516,7 @@ pfmlib_os_t pfmlib_os_perf_ext={
        .get_os_attr_info = perf_get_os_attr_info,
        .get_os_nattrs = perf_get_os_nattrs,
        .encode = pfmlib_perf_event_encode,
+       .get_scale = pfmlib_perf_event_scale,
 };
 
 
diff --git a/lib/pfmlib_priv.h b/lib/pfmlib_priv.h
index b5e2d0c..cc6307a 100644
--- a/lib/pfmlib_priv.h
+++ b/lib/pfmlib_priv.h
@@ -152,6 +152,7 @@ typedef struct {
        int                             (*get_os_attr_info)(void *this, 
pfmlib_event_desc_t *e);
        int                             (*get_os_nattrs)(void *this, 
pfmlib_event_desc_t *e);
        int                             (*encode)(void *this, const char *str, 
int dfl_plm, void *args);
+       int                             (*get_scale)(void *this, const char 
*str, int dfl_plm, void *args);
 } pfmlib_os_t;
 
 #define PFMLIB_OS_FL_ACTIVATED 0x1     /* OS layer detected */
-- 
1.9.3


------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140
_______________________________________________
perfmon2-devel mailing list
perfmon2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/perfmon2-devel

Reply via email to