From 2327110803966f3c2f0347e0e711a8173dc4886a Mon Sep 17 00:00:00 2001
From: Jin Yao <yao.jin@linux.intel.com>
Date: Tue, 19 Apr 2016 07:16:44 +0800
Subject: [PATCH 02/16] Add cache monitoring and memory bandwidth monitoring
 features
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit

The feature is only supported on Intel Xeon V4 family.

Note that this feature requires kernel CQM/MBM patch but the patch
has not been upstreamed yet (target for 4.7). So please apply following
kernel patch before using numatop cache monitoring and memory bandwidth
monitoring features.

The link to kernel patch:
https://github.com/vshiva1/linux/tree/cqm_rcfix2

Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
---
 common/cmd.c                         |  85 ++++-
 common/disp.c                        |  80 ++++-
 common/include/cmd.h                 |  30 +-
 common/include/disp.h                |   9 +
 common/include/lwp.h                 |   1 +
 common/include/os/linux/perf_event.h | 342 +++++++++++++++---
 common/include/os/os_cmd.h           |   3 +
 common/include/os/os_perf.h          |  29 ++
 common/include/os/os_util.h          |  19 +-
 common/include/os/pfwrapper.h        |   8 +
 common/include/os/plat.h             |   1 +
 common/include/perf.h                |  28 +-
 common/include/proc.h                |   4 +
 common/include/types.h               |  22 +-
 common/include/win.h                 |  81 ++++-
 common/lwp.c                         |   3 +
 common/numatop.c                     |  10 +
 common/os/os_cmd.c                   |  90 +++++
 common/os/os_page.c                  |  40 ++-
 common/os/os_perf.c                  | 262 +++++++++++++-
 common/os/os_util.c                  |  24 ++
 common/os/pfwrapper.c                | 325 ++++++++++++++++-
 common/os/plat.c                     |  16 +-
 common/perf.c                        | 161 ++++++++-
 common/proc.c                        |  13 +
 common/util.c                        |   1 +
 common/win.c                         | 674 ++++++++++++++++++++++++++++++++++-
 intel/wsm.c                          |   2 +-
 28 files changed, 2260 insertions(+), 103 deletions(-)

diff --git a/common/cmd.c b/common/cmd.c
index a7204b6..9c79f38 100644
--- a/common/cmd.c
+++ b/common/cmd.c
@@ -42,6 +42,7 @@
 #include "include/disp.h"
 #include "include/os/os_page.h"
 #include "include/os/os_cmd.h"
+#include "include/os/plat.h"
 
 static int s_rawnum_sortkey[] = {
 	SORT_KEY_RMA,
@@ -121,6 +122,18 @@ preop_switch2accdst(cmd_t *cmd, boolean_t *smpl)
 	return (os_preop_switch2accdst(cmd, smpl));
 }
 
+static int
+preop_switch2pqoscmt(cmd_t *cmd, boolean_t *smpl)
+{
+	return (os_preop_switch2pqoscmt(cmd, smpl));
+}
+
+static int
+preop_switch2pqosmbm(cmd_t *cmd, boolean_t *smpl)
+{
+	return (os_preop_switch2pqosmbm(cmd, smpl));
+}
+
 int
 op_page_next(cmd_t *cmd, boolean_t smpl)
 {	
@@ -281,6 +294,10 @@ switch_table_init(void)
 	s_switch[WIN_TYPE_RAW_NUM][CMD_3_ID].op = op_sort;
 	s_switch[WIN_TYPE_RAW_NUM][CMD_4_ID].op = op_sort;
 	s_switch[WIN_TYPE_RAW_NUM][CMD_5_ID].op = op_sort;
+	s_switch[WIN_TYPE_RAW_NUM][CMD_PQOS_CMT_ID].preop =
+		preop_switch2pqoscmt;
+	s_switch[WIN_TYPE_RAW_NUM][CMD_PQOS_CMT_ID].op =
+		op_page_next;
 
 	/*
 	 * Initialize for window type "WIN_TYPE_TOPNPROC"
@@ -291,6 +308,10 @@ switch_table_init(void)
 	s_switch[WIN_TYPE_TOPNPROC][CMD_3_ID].op = op_sort;
 	s_switch[WIN_TYPE_TOPNPROC][CMD_4_ID].op = op_sort;
 	s_switch[WIN_TYPE_TOPNPROC][CMD_5_ID].op = op_sort;
+	s_switch[WIN_TYPE_TOPNPROC][CMD_PQOS_CMT_ID].preop =
+		preop_switch2pqoscmt;
+	s_switch[WIN_TYPE_TOPNPROC][CMD_PQOS_CMT_ID].op =
+		op_page_next;
 
 	/*
 	 * Initialize for window type "WIN_TYPE_MONIPROC"
@@ -301,6 +322,10 @@ switch_table_init(void)
 	s_switch[WIN_TYPE_MONIPROC][CMD_CALLCHAIN_ID].preop =
 	    preop_switch2callchain;
 	s_switch[WIN_TYPE_MONIPROC][CMD_CALLCHAIN_ID].op = op_page_next;
+	s_switch[WIN_TYPE_MONIPROC][CMD_PQOS_CMT_ID].preop =
+		preop_switch2pqoscmt;
+	s_switch[WIN_TYPE_MONIPROC][CMD_PQOS_CMT_ID].op =
+		op_page_next;
 
 	/*
 	 * Initialize for window type "WIN_TYPE_TOPNLWP"
@@ -315,13 +340,18 @@ switch_table_init(void)
 	s_switch[WIN_TYPE_MONILWP][CMD_CALLCHAIN_ID].preop =
 	    preop_switch2callchain;
 	s_switch[WIN_TYPE_MONILWP][CMD_CALLCHAIN_ID].op = op_page_next;
+	s_switch[WIN_TYPE_MONILWP][CMD_PQOS_CMT_ID].preop =
+		preop_switch2pqoscmt;
+	s_switch[WIN_TYPE_MONILWP][CMD_PQOS_CMT_ID].op =
+		op_page_next;
 
 	/*
 	 * Initialize for window type "WIN_TYPE_LAT_PROC"
 	 */	
 	s_switch[WIN_TYPE_LAT_PROC][CMD_REFRESH_ID].preop = preop_llrefresh;
 	s_switch[WIN_TYPE_LAT_PROC][CMD_BACK_ID].preop = preop_switch2profiling;
-	s_switch[WIN_TYPE_LAT_PROC][CMD_LLCALLCHAIN_ID].op = op_switch2llcallchain;
+	s_switch[WIN_TYPE_LAT_PROC][CMD_LLCALLCHAIN_ID].op =
+		op_switch2llcallchain;
 	s_switch[WIN_TYPE_LAT_PROC][CMD_LATNODE_ID].preop = preop_switch2ln;
 	s_switch[WIN_TYPE_LAT_PROC][CMD_LATNODE_ID].op = op_page_next;
 	s_switch[WIN_TYPE_LAT_PROC][CMD_ACCDST_ID].preop = preop_switch2accdst;
@@ -337,7 +367,8 @@ switch_table_init(void)
 	 */
 	s_switch[WIN_TYPE_LAT_LWP][CMD_REFRESH_ID].preop = preop_llrefresh;
 	s_switch[WIN_TYPE_LAT_LWP][CMD_BACK_ID].preop = preop_switch2profiling;
-	s_switch[WIN_TYPE_LAT_LWP][CMD_LLCALLCHAIN_ID].op = op_switch2llcallchain;
+	s_switch[WIN_TYPE_LAT_LWP][CMD_LLCALLCHAIN_ID].op =
+		op_switch2llcallchain;
 	s_switch[WIN_TYPE_LAT_LWP][CMD_LATNODE_ID].preop = preop_switch2ln;
 	s_switch[WIN_TYPE_LAT_LWP][CMD_LATNODE_ID].op = op_page_next;
 	s_switch[WIN_TYPE_LAT_LWP][CMD_ACCDST_ID].preop = preop_switch2accdst;
@@ -409,6 +440,44 @@ switch_table_init(void)
 	 */
 	s_switch[WIN_TYPE_LLCALLCHAIN][CMD_NODE_OVERVIEW_ID].preop = NULL;
 	s_switch[WIN_TYPE_LLCALLCHAIN][CMD_NODE_OVERVIEW_ID].op = NULL;
+
+	/*
+	 * Initialize for window type "WIN_TYPE_PQOS_CMT_TOPNPROC"
+	 */
+	s_switch[WIN_TYPE_PQOS_CMT_TOPNPROC][CMD_BACK_ID].preop =
+		preop_switch2profiling;
+
+	/*
+	 * Initialize for window type "WIN_TYPE_PQOS_CMT_MONIPROC"
+	 */
+	s_switch[WIN_TYPE_PQOS_CMT_MONIPROC][CMD_BACK_ID].preop =
+		preop_switch2profiling;
+	s_switch[WIN_TYPE_PQOS_CMT_MONIPROC][CMD_PQOS_MBM_ID].preop =
+		preop_switch2pqosmbm;
+	s_switch[WIN_TYPE_PQOS_CMT_MONIPROC][CMD_PQOS_MBM_ID].op =
+		op_page_next;
+
+	/*
+	 * Initialize for window type "WIN_TYPE_PQOS_CMT_MONILWP"
+	 */
+	s_switch[WIN_TYPE_PQOS_CMT_MONILWP][CMD_BACK_ID].preop =
+		preop_switch2profiling;
+	s_switch[WIN_TYPE_PQOS_CMT_MONILWP][CMD_PQOS_MBM_ID].preop =
+		preop_switch2pqosmbm;
+	s_switch[WIN_TYPE_PQOS_CMT_MONILWP][CMD_PQOS_MBM_ID].op =
+		op_page_next;
+
+	/*
+	 * Initialize for window type "WIN_TYPE_PQOS_MBM_MONIPROC"
+	 */
+	s_switch[WIN_TYPE_PQOS_MBM_MONIPROC][CMD_BACK_ID].preop =
+		preop_switch2pqoscmt;
+
+	/*
+	 * Initialize for window type "WIN_TYPE_PQOS_MBM_MONILWP"
+	 */
+	s_switch[WIN_TYPE_PQOS_MBM_MONILWP][CMD_BACK_ID].preop =
+		preop_switch2pqoscmt;
 }
 
 static int
@@ -489,6 +558,18 @@ cmd_id_get(char ch)
 	case CMD_5_CHAR:
 		return (CMD_5_ID);
 
+	case CMD_PQOS_CMT_CHAR:
+		if (g_cmt_enabled)
+			return (CMD_PQOS_CMT_ID);
+
+		return (CMD_INVALID_ID);
+
+	case CMD_PQOS_MBM_CHAR:
+		if (g_cmt_enabled)
+			return (CMD_PQOS_MBM_ID);
+
+		return (CMD_INVALID_ID);
+
 	default:
 		return (CMD_INVALID_ID);
 	}
diff --git a/common/disp.c b/common/disp.c
index 12d9aaa..0a2907d 100644
--- a/common/disp.c
+++ b/common/disp.c
@@ -57,6 +57,26 @@ static int disp_start(void);
 static void* disp_handler(void *);
 static void* cons_handler(void *);
 
+static int mutex_cond_init(pthread_mutex_t *mutex, pthread_cond_t *cond)
+{
+	if (pthread_mutex_init(mutex, NULL) != 0) {
+		return (-1);
+	}
+
+	if (pthread_cond_init(cond, NULL) != 0) {
+		(void) pthread_mutex_destroy(mutex);
+		return (-1);
+	}
+
+	return 0;
+}
+
+static void mutex_cond_fini(pthread_mutex_t *mutex, pthread_cond_t *cond)
+{
+	pthread_mutex_destroy(mutex);
+	pthread_cond_destroy(cond);
+}
+
 /*
  * Initialization for the display control structure.
  */
@@ -64,13 +84,13 @@ static int
 disp_ctl_init(void)
 {
 	(void) memset(&s_disp_ctl, 0, sizeof (s_disp_ctl));
-	if (pthread_mutex_init(&s_disp_ctl.mutex, NULL) != 0) {
-		return (-1);
-	}
 
-	if (pthread_cond_init(&s_disp_ctl.cond, NULL) != 0) {
-		(void) pthread_mutex_destroy(&s_disp_ctl.mutex);
-		return (-1);
+	if (mutex_cond_init(&s_disp_ctl.mutex, &s_disp_ctl.cond) != 0)
+		return -1;
+
+	if (mutex_cond_init(&s_disp_ctl.mutex2, &s_disp_ctl.cond2) != 0) {
+		mutex_cond_fini(&s_disp_ctl.mutex, &s_disp_ctl.cond);
+		return -1;
 	}
 
 	s_disp_ctl.inited = B_TRUE;
@@ -84,8 +104,8 @@ static void
 disp_ctl_fini(void)
 {
 	if (s_disp_ctl.inited) {
-		(void) pthread_mutex_destroy(&s_disp_ctl.mutex);
-		(void) pthread_cond_destroy(&s_disp_ctl.cond);
+		mutex_cond_fini(&s_disp_ctl.mutex, &s_disp_ctl.cond);
+		mutex_cond_fini(&s_disp_ctl.mutex2, &s_disp_ctl.cond2);
 		s_disp_ctl.inited = B_FALSE;
 	}
 }
@@ -245,6 +265,19 @@ disp_ll_data_fail(void)
 	dispthr_flagset_lock(DISP_FLAG_LL_DATA_FAIL);
 }
 
+void disp_pqos_cmt_data_ready(int intval_ms)
+{
+	(void) pthread_mutex_lock(&s_disp_ctl.mutex);
+	s_disp_ctl.intval_ms = intval_ms;
+	dispthr_flagset_nolock(DISP_FLAG_PQOS_CMT_READY);
+	(void) pthread_mutex_unlock(&s_disp_ctl.mutex);
+}
+
+void disp_pqos_cmt_data_fail(void)
+{
+	dispthr_flagset_lock(DISP_FLAG_PQOS_CMT_FAIL);
+}
+
 /*
  * The handler of signal 'SIGWINCH'. The function sends a 'refresh'
  * command to 'cons thread' to let it do a refresh operation.
@@ -515,6 +548,7 @@ disp_handler(void *arg)
 		case DISP_FLAG_PROFILING_DATA_READY:
 		case DISP_FLAG_CALLCHAIN_DATA_READY:
 		case DISP_FLAG_LL_DATA_READY:
+		case DISP_FLAG_PQOS_CMT_READY:
 			/*
 			 * Show the page.
 			 */
@@ -525,6 +559,7 @@ disp_handler(void *arg)
 		case DISP_FLAG_PROFILING_DATA_FAIL:
 		case DISP_FLAG_CALLCHAIN_DATA_FAIL:
 		case DISP_FLAG_LL_DATA_FAIL:
+		case DISP_FLAG_PQOS_CMT_FAIL:
 			/*
 			 * Received the notification that the perf counting
 			 * was failed.
@@ -739,3 +774,32 @@ disp_go_home(void)
 	dispthr_flagset_nolock(DISP_FLAG_CMD);
 	(void) pthread_mutex_unlock(&s_disp_ctl.mutex);
 }
+
+void
+disp_flag2_set(disp_flag_t flag2)
+{
+	pthread_mutex_lock(&s_disp_ctl.mutex2);
+
+	s_disp_ctl.flag2 = flag2;
+	pthread_cond_signal(&s_disp_ctl.cond2);
+	pthread_mutex_unlock(&s_disp_ctl.mutex2);
+}
+
+disp_flag_t
+disp_flag2_wait(void)
+{
+	disp_flag_t flag2;
+
+	pthread_mutex_lock(&s_disp_ctl.mutex2);
+	flag2 = s_disp_ctl.flag2;
+
+	while (flag2 == DISP_FLAG_NONE) {
+		pthread_cond_wait(&s_disp_ctl.cond2, &s_disp_ctl.mutex2);
+		flag2 = s_disp_ctl.flag2;
+	}
+
+	s_disp_ctl.flag2 = DISP_FLAG_NONE;
+	pthread_mutex_unlock(&s_disp_ctl.mutex2);
+
+	return flag2;
+}
diff --git a/common/include/cmd.h b/common/include/cmd.h
index 4208084..c369d65 100644
--- a/common/include/cmd.h
+++ b/common/include/cmd.h
@@ -54,6 +54,8 @@ extern "C" {
 #define CMD_ACCDST_CHAR	'd'
 #define CMD_MAP_GET_CHAR	'm'
 #define CMD_MAP_STOP_CHAR	's'
+#define CMD_PQOS_CMT_CHAR	'o'
+#define CMD_PQOS_MBM_CHAR	'p'
 
 typedef enum {
 	CMD_INVALID_ID = 0,
@@ -78,10 +80,12 @@ typedef enum {
 	CMD_REFRESH_ID,
 	CMD_QUIT_ID,
 	CMD_BACK_ID,
-	CMD_RESIZE_ID
+	CMD_RESIZE_ID,
+	CMD_PQOS_CMT_ID,
+	CMD_PQOS_MBM_ID
 } cmd_id_t;
 
-#define CMD_NUM	23
+#define CMD_NUM	25
 
 typedef struct _cmd_home {
 	cmd_id_t id;
@@ -146,6 +150,20 @@ typedef struct _cmd_llcallchain {
 	char desc[WIN_DESCBUF_SIZE];
 } cmd_llcallchain_t;
 
+typedef struct _cmd_pqos_cmt {
+	cmd_id_t id;
+	pid_t pid;
+	int lwpid;
+	int flags;
+} cmd_pqos_cmt_t;
+
+typedef struct _cmd_pqos_mbm {
+	cmd_id_t id;
+	pid_t pid;
+	int lwpid;
+	int flags;
+} cmd_pqos_mbm_t;
+
 typedef union _cmd {
 	cmd_home_t home;
 	cmd_ir_normalize_t ir_normalize;
@@ -158,6 +176,8 @@ typedef union _cmd {
 	cmd_callchain_t callchain;
 	cmd_llcallchain_t llcallchain;
 	cmd_accdst_t accdst;
+	cmd_pqos_cmt_t pqos_cmt;
+	cmd_pqos_mbm_t pqos_mbm;
 } cmd_t;
 
 typedef int (*pfn_switch_preop_t)(cmd_t *, boolean_t *);
@@ -198,6 +218,12 @@ typedef struct _switch {
 #define	CMD_LLCALLCHAIN(cmd) \
 	((cmd_llcallchain_t *)(cmd))
 
+#define	CMD_PQOS_CMT(cmd) \
+	((cmd_pqos_cmt_t *)(cmd))
+
+#define	CMD_PQOS_MBM(cmd) \
+	((cmd_pqos_mbm_t *)(cmd))
+
 extern int g_sortkey;
 
 extern void switch_table_init(void);
diff --git a/common/include/disp.h b/common/include/disp.h
index d6d77cf..f9d28de 100644
--- a/common/include/disp.h
+++ b/common/include/disp.h
@@ -54,6 +54,8 @@ typedef enum {
 	DISP_FLAG_CALLCHAIN_DATA_FAIL,
 	DISP_FLAG_LL_DATA_READY,
 	DISP_FLAG_LL_DATA_FAIL,
+	DISP_FLAG_PQOS_CMT_READY,
+	DISP_FLAG_PQOS_CMT_FAIL,
 	DISP_FLAG_CMD,
 	DISP_FLAG_SCROLLUP,
 	DISP_FLAG_SCROLLDOWN,
@@ -63,10 +65,13 @@ typedef enum {
 typedef struct _disp_ctl {
 	pthread_mutex_t mutex;
 	pthread_cond_t cond;
+	pthread_mutex_t mutex2;
+	pthread_cond_t cond2;
 	pthread_t thr;
 	boolean_t inited;
 	cmd_t cmd;
 	disp_flag_t flag;
+	disp_flag_t flag2;
 	int intval_ms;
 } disp_ctl_t;
 
@@ -90,11 +95,15 @@ extern void disp_callchain_data_ready(int);
 extern void disp_callchain_data_fail(void);
 extern void disp_ll_data_ready(int);
 extern void disp_ll_data_fail(void);
+extern void disp_pqos_cmt_data_ready(int);
+extern void disp_pqos_cmt_data_fail(void);
 extern void disp_on_resize(int);
 extern void disp_intval(char *, int);
 extern void disp_dispthr_quit_wait(void);
 extern void disp_dispthr_quit_start(void);
 extern void disp_go_home(void);
+extern void disp_flag2_set(disp_flag_t);
+extern disp_flag_t disp_flag2_wait(void);
 
 #ifdef __cplusplus
 }
diff --git a/common/include/lwp.h b/common/include/lwp.h
index d18cf32..1b2ca68 100644
--- a/common/include/lwp.h
+++ b/common/include/lwp.h
@@ -57,6 +57,7 @@ typedef struct _track_lwp {
 	count_value_t *countval_arr;
 	perf_countchain_t count_chain;
 	perf_llrecgrp_t llrec_grp;
+	perf_pqos_t pqos;
 	void *perf_priv;
 } track_lwp_t;
 
diff --git a/common/include/os/linux/perf_event.h b/common/include/os/linux/perf_event.h
index 62e9f25..d97f84c 100644
--- a/common/include/os/linux/perf_event.h
+++ b/common/include/os/linux/perf_event.h
@@ -109,6 +109,7 @@ enum perf_sw_ids {
 	PERF_COUNT_SW_PAGE_FAULTS_MAJ		= 6,
 	PERF_COUNT_SW_ALIGNMENT_FAULTS		= 7,
 	PERF_COUNT_SW_EMULATION_FAULTS		= 8,
+	PERF_COUNT_SW_DUMMY			= 9,
 
 	PERF_COUNT_SW_MAX,			/* non-ABI */
 };
@@ -134,8 +135,11 @@ enum perf_event_sample_format {
 	PERF_SAMPLE_STACK_USER			= 1U << 13,
 	PERF_SAMPLE_WEIGHT			= 1U << 14,
 	PERF_SAMPLE_DATA_SRC			= 1U << 15,
+	PERF_SAMPLE_IDENTIFIER			= 1U << 16,
+	PERF_SAMPLE_TRANSACTION			= 1U << 17,
+	PERF_SAMPLE_REGS_INTR			= 1U << 18,
 
-	PERF_SAMPLE_MAX = 1U << 16,		/* non-ABI */
+	PERF_SAMPLE_MAX = 1U << 19,		/* non-ABI */
 };
 
 /*
@@ -148,17 +152,44 @@ enum perf_event_sample_format {
  * The branch types can be combined, however BRANCH_ANY covers all types
  * of branches and therefore it supersedes all the other types.
  */
-enum perf_branch_sample_type {
-	PERF_SAMPLE_BRANCH_USER		= 1U << 0, /* user branches */
-	PERF_SAMPLE_BRANCH_KERNEL	= 1U << 1, /* kernel branches */
-	PERF_SAMPLE_BRANCH_HV		= 1U << 2, /* hypervisor branches */
-
-	PERF_SAMPLE_BRANCH_ANY		= 1U << 3, /* any branch types */
-	PERF_SAMPLE_BRANCH_ANY_CALL	= 1U << 4, /* any call branch */
-	PERF_SAMPLE_BRANCH_ANY_RETURN	= 1U << 5, /* any return branch */
-	PERF_SAMPLE_BRANCH_IND_CALL	= 1U << 6, /* indirect calls */
+enum perf_branch_sample_type_shift {
+	PERF_SAMPLE_BRANCH_USER_SHIFT		= 0, /* user branches */
+	PERF_SAMPLE_BRANCH_KERNEL_SHIFT		= 1, /* kernel branches */
+	PERF_SAMPLE_BRANCH_HV_SHIFT		= 2, /* hypervisor branches */
+
+	PERF_SAMPLE_BRANCH_ANY_SHIFT		= 3, /* any branch types */
+	PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT	= 4, /* any call branch */
+	PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT	= 5, /* any return branch */
+	PERF_SAMPLE_BRANCH_IND_CALL_SHIFT	= 6, /* indirect calls */
+	PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT	= 7, /* transaction aborts */
+	PERF_SAMPLE_BRANCH_IN_TX_SHIFT		= 8, /* in transaction */
+	PERF_SAMPLE_BRANCH_NO_TX_SHIFT		= 9, /* not in transaction */
+	PERF_SAMPLE_BRANCH_COND_SHIFT		= 10, /* conditional branches */
+
+	PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT	= 11, /* call/ret stack */
+	PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT	= 12, /* indirect jumps */
+
+	PERF_SAMPLE_BRANCH_MAX_SHIFT		/* non-ABI */
+};
 
-	PERF_SAMPLE_BRANCH_MAX		= 1U << 7, /* non-ABI */
+enum perf_branch_sample_type {
+	PERF_SAMPLE_BRANCH_USER		= 1U << PERF_SAMPLE_BRANCH_USER_SHIFT,
+	PERF_SAMPLE_BRANCH_KERNEL	= 1U << PERF_SAMPLE_BRANCH_KERNEL_SHIFT,
+	PERF_SAMPLE_BRANCH_HV		= 1U << PERF_SAMPLE_BRANCH_HV_SHIFT,
+
+	PERF_SAMPLE_BRANCH_ANY		= 1U << PERF_SAMPLE_BRANCH_ANY_SHIFT,
+	PERF_SAMPLE_BRANCH_ANY_CALL	= 1U << PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT,
+	PERF_SAMPLE_BRANCH_ANY_RETURN	= 1U << PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT,
+	PERF_SAMPLE_BRANCH_IND_CALL	= 1U << PERF_SAMPLE_BRANCH_IND_CALL_SHIFT,
+	PERF_SAMPLE_BRANCH_ABORT_TX	= 1U << PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT,
+	PERF_SAMPLE_BRANCH_IN_TX	= 1U << PERF_SAMPLE_BRANCH_IN_TX_SHIFT,
+	PERF_SAMPLE_BRANCH_NO_TX	= 1U << PERF_SAMPLE_BRANCH_NO_TX_SHIFT,
+	PERF_SAMPLE_BRANCH_COND		= 1U << PERF_SAMPLE_BRANCH_COND_SHIFT,
+
+	PERF_SAMPLE_BRANCH_CALL_STACK	= 1U << PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT,
+	PERF_SAMPLE_BRANCH_IND_JUMP	= 1U << PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT,
+
+	PERF_SAMPLE_BRANCH_MAX		= 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,
 };
 
 #define PERF_SAMPLE_BRANCH_PLM_ALL \
@@ -176,6 +207,28 @@ enum perf_sample_regs_abi {
 };
 
 /*
+ * Values for the memory transaction event qualifier, mostly for
+ * abort events. Multiple bits can be set.
+ */
+enum {
+	PERF_TXN_ELISION        = (1 << 0), /* From elision */
+	PERF_TXN_TRANSACTION    = (1 << 1), /* From transaction */
+	PERF_TXN_SYNC           = (1 << 2), /* Instruction is related */
+	PERF_TXN_ASYNC          = (1 << 3), /* Instruction not related */
+	PERF_TXN_RETRY          = (1 << 4), /* Retry possible */
+	PERF_TXN_CONFLICT       = (1 << 5), /* Conflict abort */
+	PERF_TXN_CAPACITY_WRITE = (1 << 6), /* Capacity write abort */
+	PERF_TXN_CAPACITY_READ  = (1 << 7), /* Capacity read abort */
+
+	PERF_TXN_MAX	        = (1 << 8), /* non-ABI */
+
+	/* bits 32..63 are reserved for the abort code */
+
+	PERF_TXN_ABORT_MASK  = (0xffffffffULL << 32),
+	PERF_TXN_ABORT_SHIFT = 32,
+};
+
+/*
  * The format of the data returned by read() on a perf event fd,
  * as specified by attr.read_format:
  *
@@ -209,6 +262,8 @@ enum perf_event_read_format {
 #define PERF_ATTR_SIZE_VER2	80	/* add: branch_sample_type */
 #define PERF_ATTR_SIZE_VER3	96	/* add: sample_regs_user */
 					/* add: sample_stack_user */
+#define PERF_ATTR_SIZE_VER4	104	/* add: sample_regs_intr */
+#define PERF_ATTR_SIZE_VER5	112	/* add: aux_watermark */
 
 /*
  * Hardware event_id to monitor via a performance monitoring event:
@@ -272,8 +327,10 @@ struct perf_event_attr {
 
 				exclude_callchain_kernel : 1, /* exclude kernel callchains */
 				exclude_callchain_user   : 1, /* exclude user callchains */
-
-				__reserved_1   : 41;
+				mmap2          :  1, /* include mmap with inode data     */
+				comm_exec      :  1, /* flag comm events that are due to an exec */
+				use_clockid    :  1, /* use @clockid for time fields */
+				__reserved_1   : 38;
 
 	union {
 		__u32		wakeup_events;	  /* wakeup every n events */
@@ -302,8 +359,22 @@ struct perf_event_attr {
 	 */
 	__u32	sample_stack_user;
 
-	/* Align to u64. */
-	__u32	__reserved_2;
+	__s32	clockid;
+	/*
+	 * Defines set of regs to dump for each sample
+	 * state captured on:
+	 *  - precise = 0: PMU interrupt
+	 *  - precise > 0: sampled instruction
+	 *
+	 * See asm/perf_regs.h for details.
+	 */
+	__u64	sample_regs_intr;
+
+	/*
+	 * Wakeup watermark for AUX area
+	 */
+	__u32	aux_watermark;
+	__u32	__reserved_2;	/* align to __u64 */
 };
 
 #define perf_flags(attr)	(*(&(attr)->read_format + 1))
@@ -318,6 +389,8 @@ struct perf_event_attr {
 #define PERF_EVENT_IOC_PERIOD		_IOW('$', 4, __u64)
 #define PERF_EVENT_IOC_SET_OUTPUT	_IO ('$', 5)
 #define PERF_EVENT_IOC_SET_FILTER	_IOW('$', 6, char *)
+#define PERF_EVENT_IOC_ID		_IOR('$', 7, __u64 *)
+#define PERF_EVENT_IOC_SET_BPF		_IOW('$', 8, __u32)
 
 enum perf_event_ioc_flags {
 	PERF_IOC_FLAG_GROUP		= 1U << 0,
@@ -333,7 +406,7 @@ struct perf_event_mmap_page {
 	/*
 	 * Bits needed to read the hw events in user-space.
 	 *
-	 *   u32 seq, time_mult, time_shift, idx, width;
+	 *   u32 seq, time_mult, time_shift, index, width;
 	 *   u64 count, enabled, running;
 	 *   u64 cyc, time_offset;
 	 *   s64 pmc = 0;
@@ -352,11 +425,11 @@ struct perf_event_mmap_page {
 	 *       time_shift  = pc->time_shift;
 	 *     }
 	 *
-	 *     idx = pc->index;
+	 *     index = pc->index;
 	 *     count = pc->offset;
-	 *     if (pc->cap_usr_rdpmc && idx) {
+	 *     if (pc->cap_user_rdpmc && index) {
 	 *       width = pc->pmc_width;
-	 *       pmc = rdpmc(idx - 1);
+	 *       pmc = rdpmc(index - 1);
 	 *     }
 	 *
 	 *     barrier();
@@ -372,13 +445,19 @@ struct perf_event_mmap_page {
 	__u64	time_running;		/* time event on cpu */
 	union {
 		__u64	capabilities;
-		__u64	cap_usr_time  : 1,
-			cap_usr_rdpmc : 1,
-			cap_____res   : 62;
+		struct {
+			__u64	cap_bit0		: 1, /* Always 0, deprecated, see commit 860f085b74e9 */
+				cap_bit0_is_deprecated	: 1, /* Always 1, signals that bit 0 is zero */
+
+				cap_user_rdpmc		: 1, /* The RDPMC instruction can be used to read counts */
+				cap_user_time		: 1, /* The time_* fields are used */
+				cap_user_time_zero	: 1, /* The time_zero field is used */
+				cap_____res		: 59;
+		};
 	};
 
 	/*
-	 * If cap_usr_rdpmc this field provides the bit-width of the value
+	 * If cap_user_rdpmc this field provides the bit-width of the value
 	 * read using the rdpmc() or equivalent instruction. This can be used
 	 * to sign extend the result like:
 	 *
@@ -402,10 +481,10 @@ struct perf_event_mmap_page {
 	 *
 	 * Where time_offset,time_mult,time_shift and cyc are read in the
 	 * seqcount loop described above. This delta can then be added to
-	 * enabled and possible running (if idx), improving the scaling:
+	 * enabled and possible running (if index), improving the scaling:
 	 *
 	 *   enabled += delta;
-	 *   if (idx)
+	 *   if (index)
 	 *     running += delta;
 	 *
 	 *   quot = count / running;
@@ -415,26 +494,67 @@ struct perf_event_mmap_page {
 	__u16	time_shift;
 	__u32	time_mult;
 	__u64	time_offset;
+	/*
+	 * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
+	 * from sample timestamps.
+	 *
+	 *   time = timestamp - time_zero;
+	 *   quot = time / time_mult;
+	 *   rem  = time % time_mult;
+	 *   cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
+	 *
+	 * And vice versa:
+	 *
+	 *   quot = cyc >> time_shift;
+	 *   rem  = cyc & ((1 << time_shift) - 1);
+	 *   timestamp = time_zero + quot * time_mult +
+	 *               ((rem * time_mult) >> time_shift);
+	 */
+	__u64	time_zero;
+	__u32	size;			/* Header size up to __reserved[] fields. */
 
 		/*
 		 * Hole for extension of the self monitor capabilities
 		 */
 
-	__u64	__reserved[120];	/* align to 1k */
+	__u8	__reserved[118*8+4];	/* align to 1k. */
 
 	/*
 	 * Control data for the mmap() data buffer.
 	 *
-	 * User-space reading the @data_head value should issue an rmb(), on
-	 * SMP capable platforms, after reading this value -- see
-	 * perf_event_wakeup().
+	 * User-space reading the @data_head value should issue an smp_rmb(),
+	 * after reading this value.
 	 *
 	 * When the mapping is PROT_WRITE the @data_tail value should be
-	 * written by userspace to reflect the last read data. In this case
-	 * the kernel will not over-write unread data.
+	 * written by userspace to reflect the last read data, after issueing
+	 * an smp_mb() to separate the data read from the ->data_tail store.
+	 * In this case the kernel will not over-write unread data.
+	 *
+	 * See perf_output_put_handle() for the data ordering.
+	 *
+	 * data_{offset,size} indicate the location and size of the perf record
+	 * buffer within the mmapped area.
 	 */
 	__u64   data_head;		/* head in the data section */
 	__u64	data_tail;		/* user-space written tail */
+	__u64	data_offset;		/* where the buffer starts */
+	__u64	data_size;		/* data buffer size */
+
+	/*
+	 * AUX area is defined by aux_{offset,size} fields that should be set
+	 * by the userspace, so that
+	 *
+	 *   aux_offset >= data_offset + data_size
+	 *
+	 * prior to mmap()ing it. Size of the mmap()ed area should be aux_size.
+	 *
+	 * Ring buffer pointers aux_{head,tail} have the same semantics as
+	 * data_{head,tail} and same ordering rules apply.
+	 */
+	__u64	aux_head;
+	__u64	aux_tail;
+	__u64	aux_offset;
+	__u64	aux_size;
 };
 
 #define PERF_RECORD_MISC_CPUMODE_MASK		(7 << 0)
@@ -445,7 +565,16 @@ struct perf_event_mmap_page {
 #define PERF_RECORD_MISC_GUEST_KERNEL		(4 << 0)
 #define PERF_RECORD_MISC_GUEST_USER		(5 << 0)
 
+/*
+ * Indicates that /proc/PID/maps parsing are truncated by time out.
+ */
+#define PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT	(1 << 12)
+/*
+ * PERF_RECORD_MISC_MMAP_DATA and PERF_RECORD_MISC_COMM_EXEC are used on
+ * different events so can reuse the same bit position.
+ */
 #define PERF_RECORD_MISC_MMAP_DATA		(1 << 13)
+#define PERF_RECORD_MISC_COMM_EXEC		(1 << 13)
 /*
  * Indicates that the content of PERF_SAMPLE_IP points to
  * the actual instruction that triggered the event. See also
@@ -468,13 +597,28 @@ enum perf_event_type {
 	/*
 	 * If perf_event_attr.sample_id_all is set then all event types will
 	 * have the sample_type selected fields related to where/when
-	 * (identity) an event took place (TID, TIME, ID, CPU, STREAM_ID)
-	 * described in PERF_RECORD_SAMPLE below, it will be stashed just after
-	 * the perf_event_header and the fields already present for the existing
-	 * fields, i.e. at the end of the payload. That way a newer perf.data
-	 * file will be supported by older perf tools, with these new optional
-	 * fields being ignored.
+	 * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
+	 * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
+	 * just after the perf_event_header and the fields already present for
+	 * the existing fields, i.e. at the end of the payload. That way a newer
+	 * perf.data file will be supported by older perf tools, with these new
+	 * optional fields being ignored.
 	 *
+	 * struct sample_id {
+	 * 	{ u32			pid, tid; } && PERF_SAMPLE_TID
+	 * 	{ u64			time;     } && PERF_SAMPLE_TIME
+	 * 	{ u64			id;       } && PERF_SAMPLE_ID
+	 * 	{ u64			stream_id;} && PERF_SAMPLE_STREAM_ID
+	 * 	{ u32			cpu, res; } && PERF_SAMPLE_CPU
+	 *	{ u64			id;	  } && PERF_SAMPLE_IDENTIFIER
+	 * } && perf_event_attr::sample_id_all
+	 *
+	 * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.  The
+	 * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
+	 * relative to header.size.
+	 */
+
+	/*
 	 * The MMAP events record the PROT_EXEC mappings so that we can
 	 * correlate userspace IPs to code. They have the following structure:
 	 *
@@ -486,6 +630,7 @@ enum perf_event_type {
 	 *	u64				len;
 	 *	u64				pgoff;
 	 *	char				filename[];
+	 * 	struct sample_id		sample_id;
 	 * };
 	 */
 	PERF_RECORD_MMAP			= 1,
@@ -495,6 +640,7 @@ enum perf_event_type {
 	 *	struct perf_event_header	header;
 	 *	u64				id;
 	 *	u64				lost;
+	 * 	struct sample_id		sample_id;
 	 * };
 	 */
 	PERF_RECORD_LOST			= 2,
@@ -505,6 +651,7 @@ enum perf_event_type {
 	 *
 	 *	u32				pid, tid;
 	 *	char				comm[];
+	 * 	struct sample_id		sample_id;
 	 * };
 	 */
 	PERF_RECORD_COMM			= 3,
@@ -515,6 +662,7 @@ enum perf_event_type {
 	 *	u32				pid, ppid;
 	 *	u32				tid, ptid;
 	 *	u64				time;
+	 * 	struct sample_id		sample_id;
 	 * };
 	 */
 	PERF_RECORD_EXIT			= 4,
@@ -525,6 +673,7 @@ enum perf_event_type {
 	 *	u64				time;
 	 *	u64				id;
 	 *	u64				stream_id;
+	 * 	struct sample_id		sample_id;
 	 * };
 	 */
 	PERF_RECORD_THROTTLE			= 5,
@@ -536,6 +685,7 @@ enum perf_event_type {
 	 *	u32				pid, ppid;
 	 *	u32				tid, ptid;
 	 *	u64				time;
+	 * 	struct sample_id		sample_id;
 	 * };
 	 */
 	PERF_RECORD_FORK			= 7,
@@ -546,6 +696,7 @@ enum perf_event_type {
 	 *	u32				pid, tid;
 	 *
 	 *	struct read_format		values;
+	 * 	struct sample_id		sample_id;
 	 * };
 	 */
 	PERF_RECORD_READ			= 8,
@@ -554,6 +705,13 @@ enum perf_event_type {
 	 * struct {
 	 *	struct perf_event_header	header;
 	 *
+	 *	#
+	 *	# Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
+	 *	# The advantage of PERF_SAMPLE_IDENTIFIER is that its position
+	 *	# is fixed relative to header.
+	 *	#
+	 *
+	 *	{ u64			id;	  } && PERF_SAMPLE_IDENTIFIER
 	 *	{ u64			ip;	  } && PERF_SAMPLE_IP
 	 *	{ u32			pid, tid; } && PERF_SAMPLE_TID
 	 *	{ u64			time;     } && PERF_SAMPLE_TIME
@@ -582,7 +740,8 @@ enum perf_event_type {
 	 *	{ u32			size;
 	 *	  char                  data[size];}&& PERF_SAMPLE_RAW
 	 *
-	 *	{ u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
+	 *	{ u64                   nr;
+	 *        { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
 	 *
 	 * 	{ u64			abi; # enum perf_sample_regs_abi
 	 * 	  u64			regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
@@ -592,11 +751,73 @@ enum perf_event_type {
 	 * 	  u64			dyn_size; } && PERF_SAMPLE_STACK_USER
 	 *
 	 *	{ u64			weight;   } && PERF_SAMPLE_WEIGHT
-	 *	{ u64			data_src;     } && PERF_SAMPLE_DATA_SRC
+	 *	{ u64			data_src; } && PERF_SAMPLE_DATA_SRC
+	 *	{ u64			transaction; } && PERF_SAMPLE_TRANSACTION
+	 *	{ u64			abi; # enum perf_sample_regs_abi
+	 *	  u64			regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR
 	 * };
 	 */
 	PERF_RECORD_SAMPLE			= 9,
 
+	/*
+	 * The MMAP2 records are an augmented version of MMAP, they add
+	 * maj, min, ino numbers to be used to uniquely identify each mapping
+	 *
+	 * struct {
+	 *	struct perf_event_header	header;
+	 *
+	 *	u32				pid, tid;
+	 *	u64				addr;
+	 *	u64				len;
+	 *	u64				pgoff;
+	 *	u32				maj;
+	 *	u32				min;
+	 *	u64				ino;
+	 *	u64				ino_generation;
+	 *	u32				prot, flags;
+	 *	char				filename[];
+	 * 	struct sample_id		sample_id;
+	 * };
+	 */
+	PERF_RECORD_MMAP2			= 10,
+
+	/*
+	 * Records that new data landed in the AUX buffer part.
+	 *
+	 * struct {
+	 * 	struct perf_event_header	header;
+	 *
+	 * 	u64				aux_offset;
+	 * 	u64				aux_size;
+	 *	u64				flags;
+	 * 	struct sample_id		sample_id;
+	 * };
+	 */
+	PERF_RECORD_AUX				= 11,
+
+	/*
+	 * Indicates that instruction trace has started
+	 *
+	 * struct {
+	 *	struct perf_event_header	header;
+	 *	u32				pid;
+	 *	u32				tid;
+	 * };
+	 */
+	PERF_RECORD_ITRACE_START		= 12,
+
+	/*
+	 * Records the dropped/lost sample number.
+	 *
+	 * struct {
+	 *	struct perf_event_header	header;
+	 *
+	 *	u64				lost;
+	 *	struct sample_id		sample_id;
+	 * };
+	 */
+	PERF_RECORD_LOST_SAMPLES		= 13,
+
 	PERF_RECORD_MAX,			/* non-ABI */
 };
 
@@ -614,9 +835,16 @@ enum perf_callchain_context {
 	PERF_CONTEXT_MAX		= (__u64)-4095,
 };
 
-#define PERF_FLAG_FD_NO_GROUP		(1U << 0)
-#define PERF_FLAG_FD_OUTPUT		(1U << 1)
-#define PERF_FLAG_PID_CGROUP		(1U << 2) /* pid=cgroup id, per-cpu mode only */
+/**
+ * PERF_RECORD_AUX::flags bits
+ */
+#define PERF_AUX_FLAG_TRUNCATED		0x01	/* record was truncated to fit */
+#define PERF_AUX_FLAG_OVERWRITE		0x02	/* snapshot from overwrite mode */
+
+#define PERF_FLAG_FD_NO_GROUP		(1UL << 0)
+#define PERF_FLAG_FD_OUTPUT		(1UL << 1)
+#define PERF_FLAG_PID_CGROUP		(1UL << 2) /* pid=cgroup id, per-cpu mode only */
+#define PERF_FLAG_FD_CLOEXEC		(1UL << 3) /* O_CLOEXEC */
 
 union perf_mem_data_src {
 	__u64 val;
@@ -644,8 +872,8 @@ union perf_mem_data_src {
 #define PERF_MEM_LVL_MISS	0x04  /* miss level  */
 #define PERF_MEM_LVL_L1		0x08  /* L1 */
 #define PERF_MEM_LVL_LFB	0x10  /* Line Fill Buffer */
-#define PERF_MEM_LVL_L2		0x20  /* L2 hit */
-#define PERF_MEM_LVL_L3		0x40  /* L3 hit */
+#define PERF_MEM_LVL_L2		0x20  /* L2 */
+#define PERF_MEM_LVL_L3		0x40  /* L3 */
 #define PERF_MEM_LVL_LOC_RAM	0x80  /* Local DRAM */
 #define PERF_MEM_LVL_REM_RAM1	0x100 /* Remote DRAM (1 hop) */
 #define PERF_MEM_LVL_REM_RAM2	0x200 /* Remote DRAM (2 hops) */
@@ -679,6 +907,30 @@ union perf_mem_data_src {
 #define PERF_MEM_TLB_SHIFT	26
 
 #define PERF_MEM_S(a, s) \
-	(((u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
+	(((__u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
+
+/*
+ * single taken branch record layout:
+ *
+ *      from: source instruction (may not always be a branch insn)
+ *        to: branch target
+ *   mispred: branch target was mispredicted
+ * predicted: branch target was predicted
+ *
+ * support for mispred, predicted is optional. In case it
+ * is not supported mispred = predicted = 0.
+ *
+ *     in_tx: running in a hardware transaction
+ *     abort: aborting a hardware transaction
+ */
+struct perf_branch_entry {
+	__u64	from;
+	__u64	to;
+	__u64	mispred:1,  /* target mispredicted */
+		predicted:1,/* target predicted */
+		in_tx:1,    /* in transaction */
+		abort:1,    /* transaction abort */
+		reserved:60;
+};
 
 #endif /* _UAPI_LINUX_PERF_EVENT_H */
diff --git a/common/include/os/os_cmd.h b/common/include/os/os_cmd.h
index 66bb071..370ae29 100644
--- a/common/include/os/os_cmd.h
+++ b/common/include/os/os_cmd.h
@@ -49,6 +49,9 @@ extern int os_preop_back2ll(cmd_t *, boolean_t *);
 extern int os_preop_switch2callchain(cmd_t *, boolean_t *);
 extern int os_preop_switch2accdst(cmd_t *, boolean_t *);
 extern int os_preop_leavecallchain(cmd_t *, boolean_t *);
+extern int os_preop_switch2pqoscmt(cmd_t *, boolean_t *);
+extern int os_preop_switch2pqosmbm(cmd_t *, boolean_t *);
+
 extern int os_op_llmap_stop(cmd_t *, boolean_t);
 extern int os_op_lnmap_stop(cmd_t *, boolean_t);
 extern int os_op_switch2ll(cmd_t *, boolean_t);
diff --git a/common/include/os/os_perf.h b/common/include/os/os_perf.h
index 0869b8e..deceb5e 100644
--- a/common/include/os/os_perf.h
+++ b/common/include/os/os_perf.h
@@ -41,6 +41,11 @@ extern "C" {
 #define PERF_REC_NUM	512
 #define PERF_FD_NUM		NCPUS_MAX * COUNT_NUM
 #define INVALID_CODE_UMASK	(uint64_t)(-1)
+#define PERF_PQOS_CMT_MAX	10
+
+#define PERF_PQOS_FLAG_LLC	1
+#define PERF_PQOS_FLAG_TOTAL_BW	2
+#define PERF_PQOS_FLAG_LOCAL_BW	4
 
 typedef struct _os_perf_callchain {
 	unsigned int ip_num;
@@ -67,6 +72,18 @@ typedef struct _perf_cpu {
 	count_value_t countval_last;
 } perf_cpu_t;
 
+typedef struct _perf_pqos {
+	int occupancy_fd;
+	int totalbw_fd;
+	int localbw_fd;
+	uint64_t occupancy_values[3];
+	uint64_t occupancy_scaled;
+	uint64_t totalbw_values[3];
+	uint64_t totalbw_scaled;
+	uint64_t localbw_values[3];
+	uint64_t localbw_scaled;
+} perf_pqos_t;
+
 typedef int (*pfn_perf_cpu_op_t)(struct _perf_cpu *, void *);
 
 struct _perf_ctl;
@@ -75,6 +92,8 @@ struct _perf_countchain;
 struct _perf_chainrecgrp;
 struct _perf_chainrec;
 struct _perf_llrecgrp;
+struct _track_proc;
+struct _track_lwp;
 
 extern boolean_t os_profiling_started(struct _perf_ctl *);
 extern int os_profiling_start(struct _perf_ctl *, union _perf_task *);
@@ -106,6 +125,16 @@ extern char *os_perf_chain_entryname(void *, int);
 extern void os_perf_cpuarr_init(perf_cpu_t *, int, boolean_t);
 extern void os_perf_cpuarr_fini(perf_cpu_t *, int, boolean_t);
 extern int os_perf_cpuarr_refresh(perf_cpu_t *, int, int *, int, boolean_t);
+extern void os_pqos_cmt_init(perf_pqos_t *);
+extern int os_pqos_cmt_start(struct _perf_ctl *, union _perf_task *);
+extern int os_perf_pqos_cmt_smpl(struct _perf_ctl *, pid_t, int);
+extern int os_pqos_cmt_smpl(struct _perf_ctl *, union _perf_task *, int *);
+extern void os_perf_pqos_free(perf_pqos_t *);
+extern int os_pqos_cmt_proc_smpl(struct _track_proc *, void *, boolean_t *);
+extern int os_pqos_cmt_lwp_smpl(struct _track_lwp *, void *, boolean_t *);
+extern int os_pqos_cmt_proc_free(struct _track_proc *, void *, boolean_t *);
+extern boolean_t os_perf_pqos_cmt_started(struct _perf_ctl *);
+extern int os_pqos_proc_stop(struct _perf_ctl *, union _perf_task *);
 
 #ifdef __cplusplus
 }
diff --git a/common/include/os/os_util.h b/common/include/os/os_util.h
index c9b0e74..47652fc 100644
--- a/common/include/os/os_util.h
+++ b/common/include/os/os_util.h
@@ -43,10 +43,20 @@ extern "C" {
 #endif
 
 #define DIGIT_LEN_MAX	512
-#define CPU0_CPUFREQ_PATH	"/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"
-#define NODE_INFO_ROOT	"/sys/devices/system/node/"
-#define NODE_NONLINE_PATH	"/sys/devices/system/node/online"
-#define CPUINFO_PATH	"/proc/cpuinfo"
+#define CPU0_CPUFREQ_PATH \
+	"/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"
+#define NODE_INFO_ROOT \
+	"/sys/devices/system/node/"
+#define NODE_NONLINE_PATH \
+	"/sys/devices/system/node/online"
+#define CPUINFO_PATH \
+	"/proc/cpuinfo"
+#define CQM_LLC_OCCUPANCY_SCALE_PATH \
+	"/sys/devices/intel_cqm/events/llc_occupancy.scale"
+#define CQM_LLC_TOTAL_BW_SCALE_PATH \
+	"/sys/devices/intel_cqm/events/total_bytes.scale"
+#define CQM_LLC_LOCAL_BW_SCALE_PATH \
+	"/sys/devices/intel_cqm/events/local_bytes.scale"
 
 extern boolean_t os_authorized(void);
 extern int os_numatop_lock(boolean_t *);
@@ -61,6 +71,7 @@ extern boolean_t os_sysfs_cpu_enum(int, int *, int, int *);
 extern int sysfs_os_online_ncpus(void);
 extern boolean_t os_sysfs_meminfo(int, node_meminfo_t *);
 extern int os_sysfs_online_ncpus(void);
+extern int os_sysfs_cqm_llc_scale(const char*, double *);
 
 #ifdef __cplusplus
 }
diff --git a/common/include/os/pfwrapper.h b/common/include/os/pfwrapper.h
index cd4cd38..cc1502c 100644
--- a/common/include/os/pfwrapper.h
+++ b/common/include/os/pfwrapper.h
@@ -110,6 +110,7 @@ typedef struct _pf_ll_rbrec {
 extern precise_type_t g_precise;
 
 struct _perf_cpu;
+struct _perf_pqos;
 
 typedef int (*pfn_pf_event_op_t)(struct _perf_cpu *);
 
@@ -125,6 +126,13 @@ int pf_ll_start(struct _perf_cpu *);
 int pf_ll_stop(struct _perf_cpu *);
 void pf_ll_record(struct _perf_cpu *, pf_ll_rec_t *, int *);
 void pf_resource_free(struct _perf_cpu *);
+int pf_pqos_occupancy_setup(struct _perf_pqos *, int pid, int lwpid);
+int pf_pqos_totalbw_setup(struct _perf_pqos *, int pid, int lwpid);
+int pf_pqos_localbw_setup(struct _perf_pqos *, int pid, int lwpid);
+int pf_pqos_start(struct _perf_pqos *);
+int pf_pqos_stop(struct _perf_pqos *);
+void pf_pqos_record(struct _perf_pqos *);
+void pf_pqos_resource_free(struct _perf_pqos *);
 
 #ifdef __cplusplus
 }
diff --git a/common/include/os/plat.h b/common/include/os/plat.h
index fef00cb..1b72a9f 100644
--- a/common/include/os/plat.h
+++ b/common/include/os/plat.h
@@ -52,6 +52,7 @@ typedef struct _plat_event_config {
 } plat_event_config_t;
 
 extern uint64_t g_sample_period[COUNT_NUM][PRECISE_NUM];
+extern boolean_t g_cmt_enabled;
 
 typedef void (*pfn_plat_profiling_config_t)(count_id_t,
     plat_event_config_t *);
diff --git a/common/include/perf.h b/common/include/perf.h
index 6ae392b..77afe38 100644
--- a/common/include/perf.h
+++ b/common/include/perf.h
@@ -50,7 +50,9 @@ typedef enum {
 	PERF_STATUS_CALLCHAIN_STARTED,
 	PERF_STATUS_CALLCHAIN_FAILED,
 	PERF_STATUS_LL_STARTED,
-	PERF_STATUS_LL_FAILED
+	PERF_STATUS_LL_FAILED,
+	PERF_STATUS_PQOS_CMT_STARTED,
+	PERF_STATUS_PQOS_CMT_FAILED,
 } perf_status_t;
 
 typedef enum {
@@ -64,7 +66,10 @@ typedef enum {
 	PERF_LL_START_ID,
 	PERF_LL_SMPL_ID,	
 	PERF_STOP_ID,
-	PERF_QUIT_ID
+	PERF_QUIT_ID,
+	PERF_PQOS_CMT_START_ID,
+	PERF_PQOS_CMT_SMPL_ID,
+	PERF_PQOS_CMT_STOP_ID,
 } perf_taskid_t;
 
 typedef struct _task_quit {
@@ -77,6 +82,7 @@ typedef struct _task_allstop {
 
 typedef struct _task_profiling {
 	perf_taskid_t task_id;
+	boolean_t use_dispflag1;
 } task_profiling_t;
 
 typedef struct _task_partpause {
@@ -101,6 +107,13 @@ typedef struct _task_ll {
 	int lwpid;
 } task_ll_t;
 
+typedef struct _task_pqos_cmt {
+	perf_taskid_t task_id;
+	pid_t pid;
+	int lwpid;
+	int flags;
+} task_pqos_cmt_t;
+
 typedef union _perf_task {
 	task_quit_t quit;
 	task_allstop_t allstop;
@@ -109,6 +122,7 @@ typedef union _perf_task {
 	task_restore_t restore;
 	task_callchain_t callchain;
 	task_ll_t ll;
+	task_pqos_cmt_t pqos_cmt;
 } perf_task_t;
 
 typedef struct _perf_llrecgrp {
@@ -153,6 +167,7 @@ typedef struct _perf_ctl {
 	perf_task_t task;
 	boolean_t inited;
 	uint64_t last_ms;
+	uint64_t last_ms_pqos;
 } perf_ctl_t;
 
 extern precise_type_t g_precise;
@@ -162,7 +177,7 @@ extern void perf_fini(void);
 extern int perf_allstop(void);
 extern boolean_t perf_profiling_started(void);
 extern int perf_profiling_start(void);
-extern int perf_profiling_smpl(void);
+extern int perf_profiling_smpl(boolean_t);
 extern int perf_profiling_partpause(count_id_t);
 extern int perf_profiling_restore(count_id_t);
 extern boolean_t perf_callchain_started(void);
@@ -174,12 +189,19 @@ extern int perf_ll_smpl(pid_t, int);
 extern void perf_llrecgrp_reset(perf_llrecgrp_t *);
 extern void perf_countchain_reset(perf_countchain_t *);
 extern void perf_status_set(perf_status_t);
+extern void perf_status_set_no_signal(perf_status_t);
 extern void* perf_priv_alloc(boolean_t *);
 extern void perf_priv_free(void *);
 extern void perf_task_set(perf_task_t *);
 extern int perf_status_wait(perf_status_t);
 extern void perf_smpl_wait(void);
 extern void perf_ll_started_set(void);
+extern int perf_pqos_cmt_start(int, int, int);
+extern int perf_pqos_cmt_smpl(pid_t, int);
+extern int perf_pqos_active_proc_setup(int, boolean_t);
+extern boolean_t perf_pqos_cmt_started(void);
+extern int perf_pqos_cmt_stop(pid_t, int);
+extern int perf_pqos_proc_setup(int, int, int);
 
 #ifdef __cplusplus
 }
diff --git a/common/include/proc.h b/common/include/proc.h
index dc43182..65ef170 100644
--- a/common/include/proc.h
+++ b/common/include/proc.h
@@ -76,6 +76,8 @@ typedef struct _track_proc {
 	count_value_t *countval_arr;
 	perf_countchain_t count_chain;
 	perf_llrecgrp_t llrec_grp;
+	perf_pqos_t pqos;
+	boolean_t lwp_pqosed;
 	struct _track_proc *hash_prev;
 	struct _track_proc *hash_next;
 	struct _track_proc *sort_prev;
@@ -116,6 +118,8 @@ extern int proc_intval_get(track_proc_t *);
 extern void proc_profiling_clear(void);
 extern void proc_callchain_clear(void);
 extern void proc_ll_clear(track_proc_t *);
+extern void proc_pqos_func(track_proc_t *,
+	int (*func)(track_proc_t *, void *, boolean_t *));
 
 #ifdef __cplusplus
 }
diff --git a/common/include/types.h b/common/include/types.h
index 08a4821..64ae9a1 100644
--- a/common/include/types.h
+++ b/common/include/types.h
@@ -76,9 +76,9 @@ typedef enum {
 #define USEC_MS		1000
 #define	NS_MS		1000000
 #define MICROSEC	1000000
-#define GHZ			1000000000
-#define	MHZ			1000000
-#define	KHZ			1000
+#define GHZ		1000000000
+#define	MHZ		1000000
+#define	KHZ		1000
 #define	GB_BYTES	1024*1024*1024
 #define	KB_BYTES	1024
 #define TIME_NSEC_MAX	2147483647
@@ -96,17 +96,17 @@ typedef enum {
 #define SMPL_PERIOD_CORECLK_DEFAULT		SMPL_PERIOD_INFINITE
 #define SMPL_PERIOD_IR_DEFAULT			10000000
 
-#define SMPL_PERIOD_RMA_MIN				5000
-#define SMPL_PERIOD_LMA_MIN				5000
-#define SMPL_PERIOD_CLK_MIN				1000000
+#define SMPL_PERIOD_RMA_MIN			5000
+#define SMPL_PERIOD_LMA_MIN			5000
+#define SMPL_PERIOD_CLK_MIN			1000000
 #define SMPL_PERIOD_CORECLK_MIN			SMPL_PERIOD_INFINITE
-#define SMPL_PERIOD_IR_MIN				1000000
+#define SMPL_PERIOD_IR_MIN			1000000
 
-#define SMPL_PERIOD_RMA_MAX				100000
-#define SMPL_PERIOD_LMA_MAX				100000
-#define SMPL_PERIOD_CLK_MAX				100000000
+#define SMPL_PERIOD_RMA_MAX			100000
+#define SMPL_PERIOD_LMA_MAX			100000
+#define SMPL_PERIOD_CLK_MAX			100000000
 #define SMPL_PERIOD_CORECLK_MAX			SMPL_PERIOD_INFINITE
-#define SMPL_PERIOD_IR_MAX				100000000
+#define SMPL_PERIOD_IR_MAX			100000000
 
 typedef enum {
 	COUNT_INVALID = -1,
diff --git a/common/include/win.h b/common/include/win.h
index 39acecc..ca24105 100644
--- a/common/include/win.h
+++ b/common/include/win.h
@@ -41,7 +41,7 @@
 extern "C" {
 #endif
 
-#define	NUMATOP_TITLE	"NumaTOP v1.0, (C) 2013 Intel Corporation"
+#define	NUMATOP_TITLE	"NumaTOP v2.0, (C) 2015 Intel Corporation"
 #define	CMD_CAPTION		"Command: "
 #define	WIN_PROCNAME_SIZE	12
 #define	WIN_DESCBUF_SIZE	32
@@ -54,18 +54,32 @@ extern "C" {
 #define	NOTE_DEFAULT \
 	"Q: Quit; H: Home; B: Back; R: Refresh; N: Node"
 
+#define	NOTE_DEFAULT_LLC \
+	"Q: Quit; H: Home; B: Back; R: Refresh; N: Node; O: LLC OCCUPANCY"
+
 #define	NOTE_TOPNPROC_RAW \
 	"Q: Quit; H: Home; R: Refresh; I: IR Normalize; N: Node"
 
-#define	NOTE_TOPNPROC	NOTE_DEFAULT
+#define	NOTE_TOPNPROC_RAW_LLC \
+	"Q: Quit; H: Home; R: Refresh; I: IR Normalize; N: Node; O: LLC OCCUPANCY"
+
+#define NOTE_TOPNPROC	NOTE_DEFAULT
+#define	NOTE_TOPNPROC_LLC	NOTE_DEFAULT_LLC
+
 #define	NOTE_TOPNLWP	NOTE_DEFAULT
 
 #define	NOTE_MONIPROC \
 	"Q: Quit; H: Home; B: Back; R: Refresh; " \
 	"N: Node; L: Latency; C: Call-Chain"
 
+#define	NOTE_MONIPROC_LLC \
+	"Q;  H;  B;  R;  " \
+	"N: Node; L: Latency; C: Call-Chain; O: LLC OCCUPANCY"
+
 #define	NOTE_MONILWP 	NOTE_MONIPROC
 
+#define	NOTE_MONILWP_LLC	NOTE_MONIPROC_LLC
+
 #define	NOTE_NONODE \
 	"Q: Quit; H: Home; B: Back; R: Refresh"
 
@@ -73,6 +87,11 @@ extern "C" {
 #define	NOTE_NODEOVERVIEW NOTE_NONODE
 #define	NOTE_NODEDETAIL NOTE_NONODE
 #define	NOTE_CALLCHAIN	NOTE_NONODE
+#define NOTE_PQOS_CMT_TOPNPROC	NOTE_NONODE
+#define NOTE_PQOS_MBM	NOTE_NONODE
+
+#define NOTE_PQOS_CMT_MONI	\
+	"Q: Quit; H: Home; B: Back; R: Refresh; P: Memory Bandwidth"
 
 #define	NOTE_INVALID_PID \
 	"Invalid process id! (Q: Quit; H: Home)"
@@ -104,6 +123,9 @@ extern "C" {
 #define	CAPTION_AVGLAT		"LAT(ns)"
 #define	CAPTION_MEM_ALL		"MEM.ALL"
 #define	CAPTION_MEM_FREE	"MEM.FREE"
+#define CAPTION_LLC_OCCUPANCY	"LLC.OCCUPANCY(MB)"
+#define CAPTION_TOTAL_BW	"MBAND.TOTAL"
+#define CAPTION_LOCAL_BW	"MBAND.LOCAL"
 
 typedef enum {
 	WIN_TYPE_RAW_NUM = 0,
@@ -120,10 +142,15 @@ typedef enum {
 	WIN_TYPE_CALLCHAIN,
 	WIN_TYPE_LLCALLCHAIN,
 	WIN_TYPE_ACCDST_PROC,
-	WIN_TYPE_ACCDST_LWP
+	WIN_TYPE_ACCDST_LWP,
+	WIN_TYPE_PQOS_CMT_TOPNPROC,
+	WIN_TYPE_PQOS_CMT_MONIPROC,
+	WIN_TYPE_PQOS_CMT_MONILWP,
+	WIN_TYPE_PQOS_MBM_MONIPROC,
+	WIN_TYPE_PQOS_MBM_MONILWP,
 } win_type_t;
 
-#define	WIN_TYPE_NUM		15
+#define	WIN_TYPE_NUM		20
 
 typedef enum {
 	WARN_INVALID = 0,
@@ -311,6 +338,46 @@ typedef struct _dyn_llcallchain {
 	win_reg_t chain_data;
 } dyn_llcallchain_t;
 
+typedef struct _dyn_pqos_cmt_proc {
+	pid_t pid;
+	int lwpid;
+	win_reg_t summary;
+	win_reg_t caption;
+	win_reg_t data;
+	win_reg_t hint;
+} dyn_pqos_cmt_proc_t;
+
+typedef struct _pqos_cmt_proc_line {
+	win_countvalue_t value;
+	uint64_t llc_occupancy;
+	int pid;
+	int lwpid;
+	int nlwp;
+	int fd;
+	char proc_name[WIN_PROCNAME_SIZE];
+} pqos_cmt_proc_line_t;
+
+typedef struct _dyn_pqos_mbm_proc {
+	pid_t pid;
+	int lwpid;
+	win_reg_t summary;
+	win_reg_t caption;
+	win_reg_t data;
+	win_reg_t hint;
+} dyn_pqos_mbm_proc_t;
+
+typedef struct _pqos_mbm_proc_line {
+	win_countvalue_t value;
+	uint64_t totalbw_scaled;
+	uint64_t localbw_scaled;
+	int pid;
+	int lwpid;
+	int nlwp;
+	int totalbw_fd;
+	int localbw_fd;
+	char proc_name[WIN_PROCNAME_SIZE];
+} pqos_mbm_proc_line_t;
+
 typedef struct _dyn_warn {
 	win_reg_t msg;
 	win_reg_t pad;
@@ -343,6 +410,12 @@ typedef struct _dyn_warn {
 #define	DYN_LLCALLCHAIN(page) \
 	((dyn_llcallchain_t *)((page)->dyn_win.dyn))
 
+#define	DYN_PQOS_CMT_PROC(page) \
+	((dyn_pqos_cmt_proc_t *)((page)->dyn_win.dyn))
+
+#define	DYN_PQOS_MBM_PROC(page) \
+	((dyn_pqos_mbm_proc_t *)((page)->dyn_win.dyn))
+
 /* Screen dimension */
 extern int g_scr_height;
 extern int g_scr_width;
diff --git a/common/lwp.c b/common/lwp.c
index caad564..91b8533 100644
--- a/common/lwp.c
+++ b/common/lwp.c
@@ -86,6 +86,7 @@ lwp_alloc(void)
 
 	lwp->countval_arr = countval_arr;
 	lwp->cpuid_max = cpuid_max;
+	os_pqos_cmt_init(&lwp->pqos);
 	lwp->inited = B_TRUE;
 	return (lwp);
 }
@@ -113,6 +114,8 @@ lwp_free(track_lwp_t *lwp)
 	perf_countchain_reset(&lwp->count_chain);
 	perf_llrecgrp_reset(&lwp->llrec_grp);
 
+	os_perf_pqos_free(&lwp->pqos);
+
 	(void) pthread_mutex_unlock(&lwp->mutex);
 	(void) pthread_mutex_destroy(&lwp->mutex);
 
diff --git a/common/numatop.c b/common/numatop.c
index 0bdfaa1..233a68b 100644
--- a/common/numatop.c
+++ b/common/numatop.c
@@ -60,6 +60,9 @@ int g_sortkey;
 precise_type_t g_precise;
 pid_t g_numatop_pid;
 struct timeval g_tvbase;
+double g_llc_occupancy_scale;
+double g_llc_total_bw_scale;
+double g_llc_local_bw_scale;
 
 /* For automated test. */
 int g_run_secs;
@@ -219,6 +222,10 @@ main(int argc, char *argv[])
 	 */
 	os_calibrate();
 
+	os_sysfs_cqm_llc_scale(CQM_LLC_OCCUPANCY_SCALE_PATH, &g_llc_occupancy_scale);
+	os_sysfs_cqm_llc_scale(CQM_LLC_TOTAL_BW_SCALE_PATH, &g_llc_total_bw_scale);
+	os_sysfs_cqm_llc_scale(CQM_LLC_LOCAL_BW_SCALE_PATH, &g_llc_local_bw_scale);
+
 	if (map_init() != 0) {
 		goto L_EXIT3;
 	}
@@ -240,6 +247,9 @@ main(int argc, char *argv[])
 	}
 
 	debug_print(NULL, 2, "Detected %d online CPUs\n", g_ncpus);
+	debug_print(NULL, 2, "LLC scale: occupancy %.1f, total bw %.1f, local bw %.1f\n",
+		g_llc_occupancy_scale, g_llc_total_bw_scale, g_llc_local_bw_scale);
+
 	stderr_print("NumaTOP is starting ...\n");
 
 	if (disp_cons_ctl_init() != 0) {
diff --git a/common/os/os_cmd.c b/common/os/os_cmd.c
index cb3f991..8bd466a 100644
--- a/common/os/os_cmd.c
+++ b/common/os/os_cmd.c
@@ -38,6 +38,7 @@
 #include "../include/win.h"
 #include "../include/perf.h"
 #include "../include/cmd.h"
+#include "../include/disp.h"
 #include "../include/os/map.h"
 #include "../include/os/os_cmd.h"
 
@@ -62,6 +63,11 @@ os_preop_switch2profiling(cmd_t *cmd, boolean_t *smpl)
 		*smpl = B_TRUE;
 	}
 
+	if (perf_pqos_cmt_started()) {
+		perf_pqos_cmt_stop(0, 0);
+		*smpl = B_TRUE;
+	}
+
 	return (0);
 }
 
@@ -192,6 +198,90 @@ os_preop_leavecallchain(cmd_t *cmd, boolean_t *smpl)
 }
 
 int
+os_preop_switch2pqoscmt(cmd_t *cmd, boolean_t *smpl)
+{
+	page_t *cur = page_current_get();
+	win_type_t type = PAGE_WIN_TYPE(cur);
+	int ret = 0;
+
+	switch (type) {
+	case WIN_TYPE_MONIPROC:
+		CMD_PQOS_CMT(cmd)->pid = DYN_MONI_PROC(cur)->pid;
+		CMD_PQOS_CMT(cmd)->lwpid = 0;
+		CMD_PQOS_CMT(cmd)->flags = PERF_PQOS_FLAG_LLC;
+		break;
+
+	case WIN_TYPE_RAW_NUM:
+	case WIN_TYPE_TOPNPROC:
+		CMD_PQOS_CMT(cmd)->pid = 0;
+		CMD_PQOS_CMT(cmd)->lwpid = 0;
+		CMD_PQOS_CMT(cmd)->flags = PERF_PQOS_FLAG_LLC;
+		break;
+
+	case WIN_TYPE_MONILWP:
+		CMD_PQOS_CMT(cmd)->pid = DYN_MONI_LWP(cur)->pid;
+		CMD_PQOS_CMT(cmd)->lwpid = DYN_MONI_LWP(cur)->lwpid;
+		CMD_PQOS_CMT(cmd)->flags = PERF_PQOS_FLAG_LLC;
+		break;
+
+	case WIN_TYPE_PQOS_MBM_MONIPROC:
+	case WIN_TYPE_PQOS_MBM_MONILWP:
+		CMD_PQOS_CMT(cmd)->pid = DYN_PQOS_MBM_PROC(cur)->pid;
+		CMD_PQOS_CMT(cmd)->lwpid = DYN_PQOS_MBM_PROC(cur)->lwpid;
+		CMD_PQOS_CMT(cmd)->flags = PERF_PQOS_FLAG_LLC;
+		break;
+
+	default:
+		return (-1);
+	}
+
+	perf_pqos_cmt_stop(CMD_PQOS_CMT(cmd)->pid, CMD_PQOS_CMT(cmd)->lwpid);
+
+	if (perf_profiling_smpl(B_FALSE) != 0)
+		return -1;
+
+	if (disp_flag2_wait() != DISP_FLAG_PROFILING_DATA_READY)
+		return -1;
+
+	if (CMD_PQOS_CMT(cmd)->pid == 0) {
+		ret = perf_pqos_active_proc_setup(CMD_PQOS_CMT(cmd)->flags, B_FALSE);
+	} else {
+		ret = perf_pqos_proc_setup(CMD_PQOS_CMT(cmd)->pid,
+			CMD_PQOS_CMT(cmd)->lwpid, CMD_PQOS_CMT(cmd)->flags);
+	}
+
+	return (ret);
+}
+
+int
+os_preop_switch2pqosmbm(cmd_t *cmd, boolean_t *smpl)
+{
+	page_t *cur = page_current_get();
+	win_type_t type = PAGE_WIN_TYPE(cur);
+	int ret = 0;
+
+	if ((type == WIN_TYPE_PQOS_CMT_MONIPROC) || (type == WIN_TYPE_PQOS_CMT_MONILWP)) {
+
+		if (perf_profiling_smpl(B_FALSE) != 0)
+			return -1;
+
+		if (disp_flag2_wait() != DISP_FLAG_PROFILING_DATA_READY)
+			return -1;
+
+		CMD_PQOS_MBM(cmd)->pid = DYN_PQOS_CMT_PROC(cur)->pid;
+		CMD_PQOS_MBM(cmd)->lwpid = DYN_PQOS_CMT_PROC(cur)->lwpid;
+		CMD_PQOS_MBM(cmd)->flags = PERF_PQOS_FLAG_TOTAL_BW | PERF_PQOS_FLAG_LOCAL_BW;
+
+		perf_pqos_cmt_stop(CMD_PQOS_MBM(cmd)->pid, CMD_PQOS_MBM(cmd)->lwpid);
+
+		ret = perf_pqos_proc_setup(CMD_PQOS_MBM(cmd)->pid,
+			CMD_PQOS_MBM(cmd)->lwpid, CMD_PQOS_MBM(cmd)->flags);
+	}
+
+	return (ret);
+}
+
+int
 os_op_llmap_stop(cmd_t *cmd, boolean_t smpl)
 {
 	/* Not supported on Linux. */
diff --git a/common/os/os_page.c b/common/os/os_page.c
index ad0e892..1cebdfe 100644
--- a/common/os/os_page.c
+++ b/common/os/os_page.c
@@ -37,6 +37,7 @@
 #include "../include/cmd.h"
 #include "../include/page.h"
 #include "../include/perf.h"
+#include "../include/disp.h"
 #include "../include/os/os_page.h"
 
 /*
@@ -46,6 +47,7 @@ boolean_t
 os_page_smpl_start(page_t *page)
 {
 	cmd_t *cmd = PAGE_CMD(page);
+	win_type_t type = PAGE_WIN_TYPE(page);
 
 	switch (CMD_ID(cmd)) {
 	case CMD_HOME_ID:
@@ -61,7 +63,7 @@ os_page_smpl_start(page_t *page)
 	case CMD_NODE_DETAIL_ID:
 		/* fall through */
 	case CMD_CALLCHAIN_ID:
-		if (perf_profiling_smpl() == 0) {
+		if (perf_profiling_smpl(B_TRUE) == 0) {
 			return (B_TRUE);
 		}
 		break;
@@ -78,6 +80,42 @@ os_page_smpl_start(page_t *page)
 		}
 		break;
 
+	case CMD_PQOS_CMT_ID:
+		if (perf_profiling_smpl(B_FALSE) != 0)
+			break;
+
+		if (disp_flag2_wait() != DISP_FLAG_PROFILING_DATA_READY)
+			break;
+
+		if (type == WIN_TYPE_PQOS_CMT_TOPNPROC) {
+			perf_pqos_active_proc_setup(CMD_PQOS_CMT(cmd)->flags, B_TRUE);
+			if (perf_pqos_cmt_smpl(0, 0) != 0)
+				break;
+
+		} else if (type == WIN_TYPE_PQOS_CMT_MONIPROC) {
+			if (perf_pqos_cmt_smpl(CMD_PQOS_CMT(cmd)->pid, 0) != 0)
+				break;
+		} else if (type == WIN_TYPE_PQOS_CMT_MONILWP) {
+			if (perf_pqos_cmt_smpl(CMD_PQOS_CMT(cmd)->pid,
+				CMD_PQOS_CMT(cmd)->lwpid) != 0)
+				break;
+		}
+
+		return B_TRUE;
+
+	case CMD_PQOS_MBM_ID:
+		if (perf_profiling_smpl(B_FALSE) != 0)
+			break;
+
+		if (disp_flag2_wait() != DISP_FLAG_PROFILING_DATA_READY)
+			break;
+
+		if (perf_pqos_cmt_smpl(CMD_PQOS_CMT(cmd)->pid,
+			CMD_PQOS_CMT(cmd)->lwpid) != 0)
+			break;
+
+		return B_TRUE;
+
 	default:
 		break;
 	}
diff --git a/common/os/os_perf.c b/common/os/os_perf.c
index 7c07c28..cc23dca 100644
--- a/common/os/os_perf.c
+++ b/common/os/os_perf.c
@@ -523,7 +523,8 @@ boolean_t
 os_profiling_started(perf_ctl_t *ctl)
 {
 	if ((ctl->status == PERF_STATUS_PROFILING_PART_STARTED) ||
-		(ctl->status == PERF_STATUS_PROFILING_STARTED)) {
+		(ctl->status == PERF_STATUS_PROFILING_STARTED) ||
+		(ctl->status == PERF_STATUS_PQOS_CMT_STARTED)) {
 		return (B_TRUE);
 	}
 	
@@ -558,23 +559,39 @@ os_profiling_start(perf_ctl_t *ctl, perf_task_t *task)
 int
 os_profiling_smpl(perf_ctl_t *ctl, perf_task_t *task, int *intval_ms)
 {
+	task_profiling_t *t = (task_profiling_t *)task;
+	int ret = -1;
+
+/*
 	if (!perf_profiling_started()) {
 		return (-1);
 	}
-
+*/
 	proc_enum_update(0);
 	proc_callchain_clear();
 	proc_profiling_clear();
 	node_profiling_clear();
 
-	if (profiling_smpl(ctl, (task_profiling_t *)task, intval_ms) != 0) {
+	if (profiling_smpl(ctl, t, intval_ms) != 0) {
 		perf_status_set(PERF_STATUS_PROFILING_FAILED);
-		disp_profiling_data_fail();
-		return (-1);
+		goto L_EXIT;
 	}
-	
-	disp_profiling_data_ready(*intval_ms);
-	return (0);
+
+	ret = 0;
+
+L_EXIT:
+	if (ret == 0)
+		if (t->use_dispflag1)
+			disp_profiling_data_ready(*intval_ms);
+		else
+			disp_flag2_set(DISP_FLAG_PROFILING_DATA_READY);
+	else
+		if (t->use_dispflag1)
+			disp_profiling_data_fail();
+		else
+			disp_flag2_set(DISP_FLAG_PROFILING_DATA_FAIL);
+
+	return (ret);
 }
 
 int
@@ -834,6 +851,10 @@ os_allstop(void)
 	if (perf_ll_started()) {
 		ll_stop();				
 	}
+
+	if (perf_pqos_cmt_started()) {
+		proc_pqos_func(NULL, os_pqos_cmt_proc_free);
+	}
 }
 
 int
@@ -992,3 +1013,228 @@ os_perf_cpuarr_refresh(perf_cpu_t *cpu_arr, int cpu_num, int *cpuid_arr,
 	
 	return (0);
 }
+
+static int
+pqos_cmt_start(perf_ctl_t *ctl, int pid, int lwpid, int flags)
+{
+	track_proc_t *proc;
+	track_lwp_t *lwp = NULL;
+	perf_pqos_t *pqos;
+	int ret = -1;
+
+	if ((proc = proc_find(pid)) == NULL)
+		return -1;
+
+	if (lwpid == 0) {
+		pqos = &proc->pqos;
+	} else {
+		if ((lwp = proc_lwp_find(proc, lwpid)) == NULL) {
+			proc_refcount_dec(proc);
+			return -1;
+		}
+
+		pqos = &lwp->pqos;
+		proc->lwp_pqosed = B_TRUE;
+	}
+
+	memset(pqos, 0, sizeof(perf_pqos_t));
+	os_pqos_cmt_init(pqos);
+
+	if (flags & PERF_PQOS_FLAG_LLC) {
+		if (pf_pqos_occupancy_setup(pqos, pid, lwpid) != 0)
+			goto L_EXIT;
+	}
+
+	if (flags & PERF_PQOS_FLAG_TOTAL_BW) {
+		if (pf_pqos_totalbw_setup(pqos, pid, lwpid) != 0)
+			goto L_EXIT;
+	}
+
+	if (flags & PERF_PQOS_FLAG_LOCAL_BW) {
+		if (pf_pqos_localbw_setup(pqos, pid, lwpid) != 0)
+			goto L_EXIT;
+	}
+
+	/* ctl->last_ms_pqos = current_ms(); */
+
+	if (pf_pqos_start(pqos) == 0)
+		ret = 0;
+
+L_EXIT:
+	if (ret != 0)
+		pf_pqos_resource_free(pqos);
+
+	if (lwp != NULL)
+		lwp_refcount_dec(lwp);
+
+	proc_refcount_dec(proc);
+
+	return ret;
+}
+
+void os_pqos_cmt_init(perf_pqos_t *pqos)
+{
+	pqos->occupancy_fd = INVALID_FD;
+	pqos->totalbw_fd = INVALID_FD;
+	pqos->localbw_fd = INVALID_FD;
+}
+
+int
+os_pqos_cmt_start(perf_ctl_t *ctl, perf_task_t *task)
+{
+	task_pqos_cmt_t *t = (task_pqos_cmt_t *)task;
+
+	if (pqos_cmt_start(ctl, t->pid, t->lwpid, t->flags) != 0) {
+		debug_print(NULL, 2,
+			"os_pqos_cmt_start is failed for %d/%d\n",
+			t->pid, t->lwpid);
+		perf_status_set(PERF_STATUS_PQOS_CMT_FAILED);
+		return (-1);
+	}
+
+	perf_status_set(PERF_STATUS_PQOS_CMT_STARTED);
+	return (0);
+}
+
+int
+os_perf_pqos_cmt_smpl(perf_ctl_t *ctl, pid_t pid, int lwpid)
+{
+	perf_task_t task;
+	task_pqos_cmt_t *t;
+
+	perf_smpl_wait();
+	memset(&task, 0, sizeof (perf_task_t));
+	t = (task_pqos_cmt_t *)&task;
+	t->task_id = PERF_PQOS_CMT_SMPL_ID;
+	t->pid = pid;
+	t->lwpid = lwpid;
+	perf_task_set(&task);
+	return (0);
+}
+
+int
+os_pqos_cmt_smpl(perf_ctl_t *ctl, perf_task_t *task, int *intval_ms)
+{
+	task_pqos_cmt_t *t = (task_pqos_cmt_t *)task;
+	track_proc_t *proc;
+	track_lwp_t *lwp = NULL;
+	boolean_t end;
+
+	proc_enum_update(0);
+
+	if (t->pid == 0)
+		proc_pqos_func(NULL, os_pqos_cmt_proc_smpl);
+	else {
+		if ((proc = proc_find(t->pid)) == NULL) {
+			disp_pqos_cmt_data_ready(0);
+			return -1;
+		}
+
+		if (t->lwpid == 0)
+			os_pqos_cmt_proc_smpl(proc, NULL, &end);
+		else {
+			if ((lwp = proc_lwp_find(proc, t->lwpid)) == NULL) {
+				proc_refcount_dec(proc);
+				disp_pqos_cmt_data_ready(0);
+				return -1;
+			}
+
+			os_pqos_cmt_lwp_smpl(lwp, NULL, &end);
+		}
+
+		if (lwp != NULL)
+			lwp_refcount_dec(lwp);
+
+		proc_refcount_dec(proc);
+	}
+
+	*intval_ms = current_ms() - ctl->last_ms_pqos;
+	ctl->last_ms_pqos = current_ms();
+	disp_pqos_cmt_data_ready(*intval_ms);
+
+	return (0);
+}
+
+void
+os_perf_pqos_free(perf_pqos_t *pqos)
+{
+	pf_pqos_resource_free(pqos);
+}
+
+int os_pqos_cmt_proc_smpl(struct _track_proc *proc, void *arg, boolean_t *end)
+{
+	*end = B_FALSE;
+	pf_pqos_record(&proc->pqos);
+	return 0;
+}
+
+int
+os_pqos_cmt_lwp_smpl(track_lwp_t *lwp, void *arg, boolean_t *end)
+{
+	*end = B_FALSE;
+	pf_pqos_record(&lwp->pqos);
+	return 0;
+}
+
+static int
+os_pqos_cmt_lwp_free(track_lwp_t *lwp, void *arg, boolean_t *end)
+{
+	*end = B_FALSE;
+	os_perf_pqos_free(&lwp->pqos);
+	return 0;
+}
+
+int os_pqos_cmt_proc_free(struct _track_proc *proc, void *arg, boolean_t *end)
+{
+	*end = B_FALSE;
+	os_perf_pqos_free(&proc->pqos);
+
+	if (proc->lwp_pqosed) {
+		proc_lwp_traverse(proc, os_pqos_cmt_lwp_free, NULL);
+		proc->lwp_pqosed = B_FALSE;
+	}
+
+	return 0;
+}
+
+boolean_t
+os_perf_pqos_cmt_started(perf_ctl_t *ctl)
+{
+	if (ctl->status == PERF_STATUS_PQOS_CMT_STARTED)
+		return (B_TRUE);
+
+	return (B_FALSE);
+}
+
+int os_pqos_proc_stop(perf_ctl_t *ctl, perf_task_t *task)
+{
+	task_pqos_cmt_t *t = (task_pqos_cmt_t *)task;
+	track_proc_t *proc;
+	track_lwp_t *lwp = NULL;
+	boolean_t end;
+
+	if (t->pid == 0)
+		proc_pqos_func(NULL, os_pqos_cmt_proc_free);
+	else {
+		if ((proc = proc_find(t->pid)) == NULL)
+			return -1;
+
+		if (t->lwpid == 0)
+			os_pqos_cmt_proc_free(proc, NULL, &end);
+		else {
+			if ((lwp = proc_lwp_find(proc, t->lwpid)) == NULL) {
+				proc_refcount_dec(proc);
+				return -1;
+			}
+
+			os_pqos_cmt_lwp_free(lwp, NULL, &end);
+		}
+
+		if (lwp != NULL)
+			lwp_refcount_dec(lwp);
+
+		proc_refcount_dec(proc);
+	}
+
+	return (0);
+}
diff --git a/common/os/os_util.c b/common/os/os_util.c
index 68edaf7..eeaa506 100644
--- a/common/os/os_util.c
+++ b/common/os/os_util.c
@@ -39,6 +39,7 @@
 #include <sys/stat.h>
 #include <errno.h>
 #include <limits.h>
+#include <locale.h>
 #include "../include/types.h"
 #include "../include/util.h"
 #include "../include/os/os_util.h"
@@ -621,3 +622,26 @@ L_EXIT:
 	fclose(fp);
 	return (ret);
 }
+
+int
+os_sysfs_cqm_llc_scale(const char *path, double *scale)
+{
+	FILE *fp;
+	char buf[LINE_SIZE];
+
+	*scale = 0.0;
+
+	if ((fp = fopen(path, "r")) == NULL) {
+		return (-1);
+	}
+
+	if (fgets(buf, LINE_SIZE, fp) == NULL) {
+		fclose(fp);
+		return (-1);
+	}
+
+	fclose(fp);
+	*scale = strtod(buf, NULL);
+
+	return 0;
+}
diff --git a/common/os/pfwrapper.c b/common/os/pfwrapper.c
index 3da7369..ada66dc 100644
--- a/common/os/pfwrapper.c
+++ b/common/os/pfwrapper.c
@@ -36,6 +36,7 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/ioctl.h>
+#include <sys/errno.h>
 #include "../include/types.h"
 #include "../include/perf.h"
 #include "../include/util.h"
@@ -162,6 +163,10 @@ pf_profiling_setup(struct _perf_cpu *cpu, int idx, pf_conf_t *conf)
 	attr.read_format = PERF_FORMAT_GROUP |
 		PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
 
+	debug_print(NULL, 2, "pf_profiling_setup: attr.type = 0x%lx, "
+		"attr.config = 0x%lx, attr.config1 = 0x%lx\n",
+		 attr.type, attr.config, attr.config1);
+
 	if (idx == 0) {
 		attr.disabled = 1;
 		group_fd = -1;
@@ -187,7 +192,7 @@ pf_profiling_setup(struct _perf_cpu *cpu, int idx, pf_conf_t *conf)
 		cpu->map_len = s_mapsize;
 		cpu->map_mask = s_mapmask;
 	} else {
-        if (ioctl(fds[idx], PERF_EVENT_IOC_SET_OUTPUT, fds[0]) != 0) {
+	        if (ioctl(fds[idx], PERF_EVENT_IOC_SET_OUTPUT, fds[0]) != 0) {
 			debug_print(NULL, 2, "pf_profiling_setup: "
 				"PERF_EVENT_IOC_SET_OUTPUT is failed for CPU%d, COUNT%d\n",
 				cpu->cpuid, idx);
@@ -391,7 +396,7 @@ pf_profiling_record(struct _perf_cpu *cpu, pf_profiling_rec_t *rec_arr,
 
 	for (;;) {
 		if (mmap_buffer_read(mhdr, &ehdr, sizeof(ehdr)) == -1) {
-   	    	return;
+			return;
  		}
 
 		if ((size = ehdr.size - sizeof (ehdr)) <= 0) {			
@@ -631,3 +636,319 @@ pf_resource_free(struct _perf_cpu *cpu)
 		cpu->map_len = 0;
 	}
 }
+
+int
+pf_pqos_occupancy_setup(struct _perf_pqos *pqos, int pid, int lwpid)
+{
+	struct perf_event_attr attr;
+
+	memset(&attr, 0, sizeof (attr));
+	attr.type = 9;
+	attr.size = sizeof(attr);
+	attr.config = 1;
+	attr.disabled = 1;
+	attr.inherit = 1;
+	attr.read_format =
+		PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
+
+	if (lwpid == 0) {
+		if ((pqos->occupancy_fd = pf_event_open(&attr, pid, -1, -1, 0)) < 0) {
+			debug_print(NULL, 2, "pf_pqos_occupancy_setup: pf_event_open is failed "
+				"for pid %d\n", pid);
+			pqos->occupancy_fd = INVALID_FD;
+			return (-1);
+		}
+
+		debug_print(NULL, 2, "pf_pqos_occupancy_setup: pid %d, occupancy_fd = %d\n",
+			pid, pqos->occupancy_fd);
+	} else {
+		if ((pqos->occupancy_fd = pf_event_open(&attr, lwpid, -1, -1, 0)) < 0) {
+			debug_print(NULL, 2, "pf_pqos_occupancy_setup: pf_event_open is failed "
+				"for lwpid %d\n", lwpid);
+			pqos->occupancy_fd = INVALID_FD;
+			return (-1);
+		}
+
+		debug_print(NULL, 2, "pf_pqos_occupancy_setup: lwpid %d, occupancy_fd = %d\n",
+			lwpid, pqos->occupancy_fd);
+	}
+
+	return (0);
+}
+
+int
+pf_pqos_totalbw_setup(struct _perf_pqos *pqos, int pid, int lwpid)
+{
+	struct perf_event_attr attr;
+
+	memset(&attr, 0, sizeof (attr));
+	attr.type = 9;
+	attr.size = sizeof(attr);
+	attr.config = 2;
+	attr.disabled = 1;
+	attr.inherit = 1;
+	attr.read_format =
+		PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
+
+	if (lwpid == 0) {
+		if ((pqos->totalbw_fd = pf_event_open(&attr, pid, -1, -1, 0)) < 0) {
+			debug_print(NULL, 2, "pf_pqos_totalbw_setup: pf_event_open is failed "
+				"for pid %d\n", pid);
+			pqos->totalbw_fd = INVALID_FD;
+			return (-1);
+		}
+
+		debug_print(NULL, 2, "pf_pqos_totalbw_setup: pid %d, totalbw_fd = %d\n",
+			pid, pqos->totalbw_fd);
+	} else {
+		if ((pqos->totalbw_fd = pf_event_open(&attr, lwpid, -1, -1, 0)) < 0) {
+			debug_print(NULL, 2, "pf_pqos_totalbw_setup: pf_event_open is failed "
+				"for lwpid %d\n", lwpid);
+			pqos->totalbw_fd = INVALID_FD;
+			return (-1);
+		}
+
+		debug_print(NULL, 2, "pf_pqos_totalbw_setup: lwpid %d, totalbw_fd = %d\n",
+			lwpid, pqos->totalbw_fd);
+	}
+
+	return (0);
+}
+
+int
+pf_pqos_localbw_setup(struct _perf_pqos *pqos, int pid, int lwpid)
+{
+	struct perf_event_attr attr;
+
+	memset(&attr, 0, sizeof (attr));
+	attr.type = 9;
+	attr.size = sizeof(attr);
+	attr.config = 3;
+	attr.disabled = 1;
+	attr.inherit = 1;
+	attr.read_format =
+		PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
+
+	if (lwpid == 0) {
+		if ((pqos->localbw_fd = pf_event_open(&attr, pid, -1, -1, 0)) < 0) {
+			debug_print(NULL, 2, "pf_pqos_localbw_setup: pf_event_open is failed "
+				"for pid %d\n", pid);
+			pqos->localbw_fd = INVALID_FD;
+			return (-1);
+		}
+
+		debug_print(NULL, 2, "pf_pqos_localbw_setup: pid %d, localbw_fd = %d\n",
+			pid, pqos->localbw_fd);
+	} else {
+		if ((pqos->localbw_fd = pf_event_open(&attr, lwpid, -1, -1, 0)) < 0) {
+			debug_print(NULL, 2, "pf_pqos_localbw_setup: pf_event_open is failed "
+				"for lwpid %d\n", lwpid);
+			pqos->localbw_fd = INVALID_FD;
+			return (-1);
+		}
+
+		debug_print(NULL, 2, "pf_pqos_localbw_setup: lwpid %d, localbw_fd = %d\n",
+			lwpid, pqos->localbw_fd);
+	}
+
+	return (0);
+}
+
+int
+pf_pqos_start(struct _perf_pqos *pqos)
+{
+	if (pqos->occupancy_fd != INVALID_FD) {
+		debug_print(NULL, 2, "pf_pqos_start: occupancy_fd = %d\n",
+			pqos->occupancy_fd);
+		ioctl(pqos->occupancy_fd, PERF_EVENT_IOC_ENABLE, 0);
+	}
+
+	if (pqos->totalbw_fd != INVALID_FD) {
+		debug_print(NULL, 2, "pf_pqos_start: totalbw_fd = %d\n",
+			pqos->totalbw_fd);
+		ioctl(pqos->totalbw_fd, PERF_EVENT_IOC_ENABLE, 0);
+	}
+
+	if (pqos->localbw_fd != INVALID_FD) {
+		debug_print(NULL, 2, "pf_pqos_start: localbw_fd = %d\n",
+			pqos->localbw_fd);
+		ioctl(pqos->localbw_fd, PERF_EVENT_IOC_ENABLE, 0);
+	}
+
+	return (0);
+}
+
+int
+pf_pqos_stop(struct _perf_pqos *pqos)
+{
+	if (pqos->occupancy_fd != INVALID_FD) {
+		ioctl(pqos->occupancy_fd, PERF_EVENT_IOC_DISABLE, 0);
+	}
+
+	if (pqos->totalbw_fd != INVALID_FD) {
+		ioctl(pqos->totalbw_fd, PERF_EVENT_IOC_DISABLE, 0);
+	}
+
+	if (pqos->localbw_fd != INVALID_FD) {
+		ioctl(pqos->localbw_fd, PERF_EVENT_IOC_DISABLE, 0);
+	}
+
+	return (0);
+}
+
+static int
+read_fd(int fd, void *buf, int bytes)
+{
+	int left = bytes, ret;
+
+	while (left > 0) {
+		if (((ret = read(fd, buf, left)) < 0) &&
+			(errno == EINTR)) {
+			debug_print(NULL, 2, "read_fd: read fd %d failed (ret = %d, errno = %d)\n",
+				fd, ret, errno);
+			continue;
+		}
+
+		if (ret < 0) {
+			debug_print(NULL, 2, "read_fd: read fd %d failed (ret = %d)\n",
+				fd, ret);
+			return ret;
+		}
+
+		left -= ret;
+		buf += ret;
+	}
+
+	return 0;
+}
+
+void
+pf_pqos_record(struct _perf_pqos *pqos)
+{
+	uint64_t values[3];
+
+	/*
+	 * struct read_format {
+	 *	{ u64	value; }
+	 *	{ u64	time_enabled; }
+	 *	{ u64	time_running; }
+	 * };
+	 */
+
+	if (pqos->occupancy_fd != INVALID_FD) {
+		if (read_fd(pqos->occupancy_fd, values,
+			sizeof(values)) != 0) {
+
+			debug_print(NULL, 2,
+				"pf_pqos_record: read from occupancy_fd %d failed\n",
+				pqos->occupancy_fd);
+		}
+
+		pqos->occupancy_scaled = scale(pqos->occupancy_values[0],
+			values[1] - pqos->occupancy_values[1],
+			values[2] - pqos->occupancy_values[2]);
+
+		debug_print(NULL, 2, "pf_pqos_record: occupancy_fd %d: "
+			"%" PRIu64 ", %" PRIu64 ", %" PRIu64 "\n",
+			pqos->occupancy_fd, pqos->occupancy_values[0],
+			values[1] - pqos->occupancy_values[1],
+			values[2] - pqos->occupancy_values[2]);
+
+		memcpy(pqos->occupancy_values, values, sizeof(values));
+	}
+
+	if (pqos->totalbw_fd != INVALID_FD) {
+		if (read_fd(pqos->totalbw_fd, values, sizeof(values)) != 0) {
+			debug_print(NULL, 2,
+				"pf_pqos_record: read from totalbw_fd %d failed\n",
+				pqos->totalbw_fd);
+		}
+
+		if (values[0] > pqos->totalbw_values[0]) {
+			pqos->totalbw_scaled = scale(values[0] - pqos->totalbw_values[0],
+				values[1] - pqos->totalbw_values[1],
+				values[2] - pqos->totalbw_values[2]);
+
+			debug_print(NULL, 2, "pf_pqos_record: totalbw_fd %d: "
+				"%" PRIu64 ", %" PRIu64 ", %" PRIu64 "\n",
+				pqos->totalbw_fd,
+				values[0] - pqos->totalbw_values[0],
+				values[1] - pqos->totalbw_values[1],
+				values[2] - pqos->totalbw_values[2]);
+		} else {
+			pqos->totalbw_scaled = scale(values[0],
+				values[1],
+				values[2]);
+
+			debug_print(NULL, 2, "pf_pqos_record: totalbw_fd %d: "
+				"%" PRIu64 ", %" PRIu64 ", %" PRIu64 "\n",
+				pqos->totalbw_fd,
+				values[0],
+				values[1],
+				values[2]);
+		}
+
+		memcpy(pqos->totalbw_values, values, sizeof(values));
+	}
+
+	if (pqos->localbw_fd != INVALID_FD) {
+		if (read_fd(pqos->localbw_fd, values, sizeof(values)) != 0) {
+			debug_print(NULL, 2,
+				"pf_pqos_record: read from localbw_fd %d failed\n",
+				pqos->localbw_fd);
+		}
+
+		if (values[0] > pqos->localbw_values[0]) {
+			pqos->localbw_scaled = scale(values[0] - pqos->localbw_values[0],
+				values[1] - pqos->localbw_values[1],
+				values[2] - pqos->localbw_values[2]);
+
+			debug_print(NULL, 2, "pf_pqos_record: localbw_fd %d: "
+				"%" PRIu64 ", %" PRIu64 ", %" PRIu64 "\n",
+				pqos->localbw_fd,
+				values[0] - pqos->localbw_values[0],
+				values[1] - pqos->localbw_values[1],
+				values[2] - pqos->localbw_values[2]);
+		} else {
+			pqos->localbw_scaled = scale(values[0],
+				values[1],
+				values[2]);
+
+			debug_print(NULL, 2, "pf_pqos_record: localbw_fd %d: "
+				"%" PRIu64 ", %" PRIu64 ", %" PRIu64 "\n",
+				pqos->localbw_scaled,
+				values[0],
+				values[1],
+				values[2]);
+		}
+
+		memcpy(pqos->localbw_values, values, sizeof(values));
+	}
+}
+
+void
+pf_pqos_resource_free(struct _perf_pqos *pqos)
+{
+	if (pqos->occupancy_fd != INVALID_FD) {
+		debug_print(NULL, 2, "pf_pqos_resource_free: occupancy_fd %d\n",
+			pqos->occupancy_fd);
+		close(pqos->occupancy_fd);
+	}
+
+	if (pqos->totalbw_fd != INVALID_FD) {
+		debug_print(NULL, 2, "pf_pqos_resource_free: totalbw_fd %d\n",
+			pqos->totalbw_fd);
+		close(pqos->totalbw_fd);
+	}
+
+	if (pqos->localbw_fd != INVALID_FD) {
+		debug_print(NULL, 2, "pf_pqos_resource_free: localbw_fd %d\n",
+			pqos->localbw_fd);
+		close(pqos->localbw_fd);
+	}
+
+	memset(pqos, 0, sizeof(struct _perf_pqos));
+	pqos->occupancy_fd = INVALID_FD;
+	pqos->totalbw_fd = INVALID_FD;
+	pqos->localbw_fd = INVALID_FD;
+}
diff --git a/common/os/plat.c b/common/os/plat.c
index f753387..bb1f166 100644
--- a/common/os/plat.c
+++ b/common/os/plat.c
@@ -43,6 +43,8 @@
 #include "../../intel/include/snb.h"
 #include "../../intel/include/bdw.h"
 
+boolean_t g_cmt_enabled;
+
 static pfn_plat_profiling_config_t
 s_plat_profiling_config[CPU_TYPE_NUM] = {
 	NULL,
@@ -91,10 +93,12 @@ static cpu_type_t s_cpu_type;
 int
 plat_detect(void)
 {
+	int ret = -1;
+
 	if ((s_cpu_type = cpu_type_get()) == CPU_UNSUP) {
 		return (-1);
 	}
-		
+
 	switch (s_cpu_type) {
 	case CPU_WSM_EX:
 		/* fall through */
@@ -110,14 +114,16 @@ plat_detect(void)
 		/* fall through */
 	case CPU_HSX:
 		/* fall through */
-	case CPU_BDX:	
-		return (0);
-		
+	case CPU_BDX:
+		ret = 0;
+		break;
 	default:
 		break;
 	}
 
-	return (-1);
+	g_cmt_enabled = (s_cpu_type == CPU_BDX) ? B_TRUE : B_FALSE;
+
+	return (ret);
 }
 
 /*
diff --git a/common/perf.c b/common/perf.c
index a45a8f5..05fef4b 100644
--- a/common/perf.c
+++ b/common/perf.c
@@ -70,6 +70,13 @@ uint64_t g_sample_period[COUNT_NUM][PRECISE_NUM] = {
 	}
 };
 
+typedef struct _perf_pqos_arg {
+	pid_t pid;
+	int lwpid;
+} perf_pqos_arg_t;
+
+static perf_pqos_arg_t s_pqos_arg[PERF_PQOS_CMT_MAX];
+
 static boolean_t
 task_valid(perf_task_t *task)
 {
@@ -93,6 +100,10 @@ task_valid(perf_task_t *task)
 	case PERF_STOP_ID:
 		/* fall through */
 	case PERF_QUIT_ID:
+		/* fall through */
+	case PERF_PQOS_CMT_START_ID:
+	case PERF_PQOS_CMT_SMPL_ID:
+	case PERF_PQOS_CMT_STOP_ID:
 		return (B_TRUE);
 	default:
 		break;
@@ -119,6 +130,14 @@ perf_status_set(perf_status_t status)
 	(void) pthread_mutex_unlock(&s_perf_ctl.status_mutex);
 }
 
+void
+perf_status_set_no_signal(perf_status_t status)
+{
+	(void) pthread_mutex_lock(&s_perf_ctl.status_mutex);
+	s_perf_ctl.status = status;
+	(void) pthread_mutex_unlock(&s_perf_ctl.status_mutex);
+}
+
 static boolean_t
 status_failed(perf_status_t status)
 {
@@ -238,6 +257,19 @@ perf_handler(void *arg)
 			os_ll_smpl(&s_perf_ctl, &task, &intval_ms);
 			break;
 
+		case PERF_PQOS_CMT_START_ID:
+			os_pqos_cmt_start(&s_perf_ctl, &task);
+			break;
+
+		case PERF_PQOS_CMT_SMPL_ID:
+			os_pqos_cmt_smpl(&s_perf_ctl, &task, &intval_ms);
+			break;
+
+		case PERF_PQOS_CMT_STOP_ID:
+			os_pqos_proc_stop(&s_perf_ctl, &task);
+			perf_status_set(PERF_STATUS_PROFILING_STARTED);
+			break;
+
 		default:
 			break;
 		}
@@ -411,7 +443,7 @@ perf_smpl_wait(void)
 }
 
 int
-perf_profiling_smpl(void)
+perf_profiling_smpl(boolean_t use_dispflag1)
 {
 	perf_task_t task;
 	task_profiling_t *t;
@@ -420,6 +452,7 @@ perf_profiling_smpl(void)
 	(void) memset(&task, 0, sizeof (perf_task_t));
 	t = (task_profiling_t *)&task;
 	t->task_id = PERF_PROFILING_SMPL_ID;
+	t->use_dispflag1 = use_dispflag1;
 	perf_task_set(&task);
 	return (0);
 }
@@ -521,3 +554,129 @@ perf_ll_started_set(void)
 {
 	perf_status_set(PERF_STATUS_LL_STARTED);
 }
+
+int
+perf_pqos_cmt_start(int pid, int lwpid, int flags)
+{
+	perf_task_t task;
+	task_pqos_cmt_t *t;
+
+	(void) memset(&task, 0, sizeof (perf_task_t));
+	t = (task_pqos_cmt_t *)&task;
+	t->task_id = PERF_PQOS_CMT_START_ID;
+	t->pid = pid;
+	t->lwpid = lwpid;
+	t->flags = flags;
+	perf_task_set(&task);
+	return (perf_status_wait(PERF_STATUS_PQOS_CMT_STARTED));
+}
+
+int
+perf_pqos_cmt_smpl(pid_t pid, int lwpid)
+{
+	return (os_perf_pqos_cmt_smpl(&s_perf_ctl, pid, lwpid));
+}
+
+int perf_pqos_active_proc_setup(int flags, boolean_t refresh)
+{
+	int nprocs, nlwps, i, j = 0, pqos_num;
+	track_proc_t *proc;
+
+	proc_lwp_count(&nprocs, &nlwps);
+	pqos_num = MIN(nprocs, PERF_PQOS_CMT_MAX);
+
+	memset(s_pqos_arg, 0, sizeof(s_pqos_arg));
+
+	proc_group_lock();
+	proc_resort(SORT_KEY_CPU);
+
+	for (i = 0; i < pqos_num; i++) {
+		if ((proc = proc_sort_next()) == NULL) {
+			break;
+		}
+
+		if (proc->pqos.occupancy_fd == INVALID_FD) {
+			s_pqos_arg[j].pid = proc->pid;
+			j++;
+		}
+	}
+
+	for (i = pqos_num; i < nprocs; i++) {
+		if ((proc = proc_sort_next()) == NULL) {
+			break;
+		}
+
+		if (proc->pqos.occupancy_fd != INVALID_FD)
+			os_perf_pqos_free(&proc->pqos);
+	}
+
+	proc_group_unlock();
+
+	for (i = 0; i < j; i++) {
+		if (perf_pqos_cmt_start(s_pqos_arg[i].pid, 0, flags) != 0)
+			return -1;
+	}
+
+	if ((j > 0) && (!refresh))
+		s_perf_ctl.last_ms_pqos = current_ms();
+
+	return 0;
+}
+
+boolean_t
+perf_pqos_cmt_started(void)
+{
+	return (os_perf_pqos_cmt_started(&s_perf_ctl));
+}
+
+int
+perf_pqos_cmt_stop(pid_t pid, int lwpid)
+{
+	perf_task_t task;
+	task_pqos_cmt_t *t;
+
+	(void) memset(&task, 0, sizeof (perf_task_t));
+	t = (task_pqos_cmt_t *)&task;
+	t->task_id = PERF_PQOS_CMT_STOP_ID;
+	t->pid = pid;
+	t->lwpid = lwpid;
+	perf_task_set(&task);
+	return (perf_status_wait(PERF_STATUS_PROFILING_STARTED));
+}
+
+int perf_pqos_proc_setup(int pid, int lwpid, int flags)
+{
+	track_proc_t *proc;
+	track_lwp_t *lwp = NULL;
+	int ret = 0;
+
+	if ((proc = proc_find(pid)) == NULL)
+		return -1;
+
+	if (proc->pqos.occupancy_fd != INVALID_FD) {
+		goto L_EXIT;
+	}
+
+	if (lwpid != 0) {
+		if ((lwp = proc_lwp_find(proc, lwpid)) == NULL) {
+			ret = -1;
+			goto L_EXIT;
+		}
+
+		if (lwp->pqos.occupancy_fd != INVALID_FD) {
+			goto L_EXIT;
+		}
+	}
+
+	if (perf_pqos_cmt_start(pid, lwpid, flags) != 0)
+		ret = -1;
+
+	s_perf_ctl.last_ms_pqos = current_ms();
+
+L_EXIT:
+	if (lwp != NULL)
+		lwp_refcount_dec(lwp);
+
+	proc_refcount_dec(proc);
+	return ret;
+}
diff --git a/common/proc.c b/common/proc.c
index b5f9097..357294e 100644
--- a/common/proc.c
+++ b/common/proc.c
@@ -114,6 +114,8 @@ proc_free(track_proc_t *proc)
 	perf_countchain_reset(&proc->count_chain);
 	perf_llrecgrp_reset(&proc->llrec_grp);
 
+	os_perf_pqos_free(&proc->pqos);
+
 	(void) pthread_mutex_unlock(&proc->mutex);
 	(void) pthread_mutex_destroy(&proc->mutex);
 	free(proc);
@@ -280,6 +282,7 @@ proc_alloc(void)
 	proc->pid = -1;
 	proc->countval_arr = countval_arr;
 	proc->cpuid_max = cpuid_max;
+	os_pqos_cmt_init(&proc->pqos);
 	proc->inited = B_TRUE;
 	return (proc);
 }
@@ -996,3 +999,13 @@ proc_ll_clear(track_proc_t *proc)
 		proc_traverse(ll_clear, NULL);
 	}
 }
+
+void proc_pqos_func(track_proc_t *proc,
+	int (*func)(track_proc_t *, void *, boolean_t *))
+{
+	if (proc == NULL) {
+		pthread_mutex_lock(&s_proc_group.mutex);
+		proc_traverse(func, NULL);
+		pthread_mutex_unlock(&s_proc_group.mutex);
+	}
+}
diff --git a/common/util.c b/common/util.c
index dc4c8a1..83562de 100644
--- a/common/util.c
+++ b/common/util.c
@@ -374,6 +374,7 @@ cpu_type_get(void)
 
 	if (family == 6) {
 		model = (ext_model << 4) + model;
+
 		switch (model) {
 		case 26:
 			type = CPU_NHM_EP;
diff --git a/common/win.c b/common/win.c
index 034481d..cff5813 100644
--- a/common/win.c
+++ b/common/win.c
@@ -51,6 +51,10 @@
 #include "include/os/os_util.h"
 #include "include/os/os_win.h"
 
+extern double g_llc_occupancy_scale;
+extern double g_llc_total_bw_scale;
+extern double g_llc_local_bw_scale;
+
 static boolean_t s_first_load = B_TRUE;
 static win_reg_t s_note_reg;
 static win_reg_t s_title_reg;
@@ -497,7 +501,7 @@ load_msg_show(void)
 }
 
 /*
- * Show the title "NumaTop v1.0, (C) 2012 Intel Corporation"
+ * Show the title "NumaTop v2.0, (C) 2015 Intel Corporation"
  */
 void
 win_title_show(void)
@@ -514,8 +518,11 @@ void
 win_note_show(char *note)
 {
 	char *content;
+	char *p;
+
+	p = (g_cmt_enabled)? NOTE_DEFAULT_LLC : NOTE_DEFAULT;
 
-	content = (note != NULL) ? note : NOTE_DEFAULT;
+	content = (note != NULL) ? note : p;
 	reg_erase(&s_note_reg);
 	reg_line_write(&s_note_reg, 0, ALIGN_LEFT, content);
 	reg_refresh(&s_note_reg);
@@ -529,6 +536,8 @@ win_note_show(char *note)
 static boolean_t
 topnproc_win_draw(dyn_win_t *win)
 {
+	char *note;
+
 	win_title_show();
 	if (s_first_load) {
 		s_first_load = B_FALSE;
@@ -541,9 +550,13 @@ topnproc_win_draw(dyn_win_t *win)
 	topnproc_data_show(win);
 
 	if (win->type == WIN_TYPE_TOPNPROC) {
-		win_note_show(NOTE_TOPNPROC);
+		note = (g_cmt_enabled)?
+			NOTE_TOPNPROC_LLC : NOTE_TOPNPROC;
+		win_note_show(note);
 	} else {
-		win_note_show(NOTE_TOPNPROC_RAW);
+		note = (g_cmt_enabled)?
+			NOTE_TOPNPROC_RAW_LLC : NOTE_TOPNPROC_RAW;
+		win_note_show(note);
 	}
 
 	reg_update_all();
@@ -856,12 +869,14 @@ static boolean_t
 moniproc_win_draw(dyn_win_t *win)
 {
 	boolean_t note_out, ret;
+	char *p;
 
 	win_title_show();
 	ret = moniproc_data_show(win, &note_out);
 
 	if (!note_out) {
-		win_note_show(NOTE_MONIPROC);
+		p = (g_cmt_enabled)? NOTE_MONIPROC_LLC : NOTE_MONIPROC;
+		win_note_show(p);
 	}
 
 	reg_update_all();
@@ -998,12 +1013,14 @@ static boolean_t
 monilwp_win_draw(dyn_win_t *win)
 {
 	boolean_t note_out, ret;
+	char *p;
 
 	win_title_show();
 	ret = monilwp_data_show(win, &note_out);
 
 	if (!note_out) {
-		win_note_show(NOTE_MONILWP);
+		p = (g_cmt_enabled)? NOTE_MONILWP_LLC : NOTE_MONILWP;
+		win_note_show(p);
 	}
 
 	reg_update_all();
@@ -2825,6 +2842,631 @@ accdst_win_draw(dyn_win_t *win)
 	return (ret);
 }
 
+static void
+pqos_cmt_proc_data_build(char *buf, int size,
+	pqos_cmt_proc_line_t *line)
+{
+	win_countvalue_t *value = &line->value;
+	char tmp[32], id[16];
+
+	if (line->lwpid == 0)
+		snprintf(id, sizeof(id), "%d", line->pid);
+	else
+		snprintf(id, sizeof(id), "%d", line->lwpid);
+
+	if (line->fd == INVALID_FD)
+		snprintf(tmp, sizeof(tmp), "%s", id);
+	else
+		snprintf(tmp, sizeof(tmp), "*%s", id);
+
+	snprintf(buf, size,
+	    "%6s%15s%11.1f%11.1f%21.1f%10.1f",
+	    tmp, line->proc_name,
+	    value->rma, value->lma,
+	    ratio(line->llc_occupancy * g_llc_occupancy_scale,
+	        1048576),
+	    value->cpu * 100);
+}
+
+static void
+pqos_cmt_proc_str_build(char *buf, int size, int idx, void *pv)
+{
+	pqos_cmt_proc_line_t *lines = (pqos_cmt_proc_line_t *)pv;
+	pqos_cmt_proc_line_t *line = &lines[idx];
+
+	pqos_cmt_proc_data_build(buf, size, line);
+}
+
+static void
+pqos_cmt_proc_line_get(win_reg_t *r, int idx, char *line, int size)
+{
+	pqos_cmt_proc_line_t *lines;
+
+	lines = (pqos_cmt_proc_line_t *)(r->buf);
+	pqos_cmt_proc_str_build(line, size, idx, (void *)lines);
+}
+
+static void
+pqos_cmt_proc_data_save(track_proc_t *proc, track_lwp_t *lwp, int intval,
+	pqos_cmt_proc_line_t *line)
+{
+	(void) memset(line, 0, sizeof (pqos_cmt_proc_line_t));
+
+	(void) strncpy(line->proc_name, proc->name, sizeof (line->proc_name));
+	line->proc_name[WIN_PROCNAME_SIZE - 1] = 0;
+	line->pid = proc->pid;
+	line->nlwp = proc_nlwp(proc);
+
+	if (lwp == NULL) {
+		line->llc_occupancy = proc->pqos.occupancy_scaled;
+		line->fd = proc->pqos.occupancy_fd;
+
+		win_countvalue_fill(&line->value, proc->countval_arr,
+			proc->cpuid_max, NODE_ALL, intval, g_ncpus);
+
+	} else {
+		line->llc_occupancy = lwp->pqos.occupancy_scaled;
+		line->fd = lwp->pqos.occupancy_fd;
+		line->lwpid = lwp->id;
+
+		win_countvalue_fill(&line->value, lwp->countval_arr,
+			lwp->cpuid_max, NODE_ALL, intval, g_ncpus);
+	}
+}
+
+static dyn_pqos_cmt_proc_t *
+pqos_cmt_dyn_create_proc(page_t *page, pid_t pid, int lwpid, win_type_t *type)
+{
+	dyn_pqos_cmt_proc_t *dyn;
+	void *buf;
+	int i;
+
+	if ((buf = zalloc(sizeof (pqos_cmt_proc_line_t) *
+	    WIN_NLINES_MAX)) == NULL) {
+		return (NULL);
+	}
+	if ((dyn = zalloc(sizeof (dyn_pqos_cmt_proc_t))) == NULL) {
+		free(buf);
+		return (NULL);
+	}
+
+	if ((i = reg_init(&dyn->summary, 0, 1, g_scr_width, 2, A_BOLD)) < 0)
+		goto L_EXIT;
+	if ((i = reg_init(&dyn->caption, 0, i, g_scr_width, 2, A_BOLD | A_UNDERLINE)) < 0)
+		goto L_EXIT;
+	if ((i = reg_init(&dyn->data, 0, i, g_scr_width, g_scr_height - i - 5, 0)) < 0)
+		goto L_EXIT;
+
+	reg_buf_init(&dyn->data, buf, pqos_cmt_proc_line_get);
+
+	reg_scroll_init(&dyn->data, B_TRUE);
+	(void) reg_init(&dyn->hint, 0, i, g_scr_width,
+	    g_scr_height - i - 1, A_BOLD);
+
+	if (pid == 0)
+		*type = WIN_TYPE_PQOS_CMT_TOPNPROC;
+	else if (lwpid == 0)
+		*type = WIN_TYPE_PQOS_CMT_MONIPROC;
+	else
+		*type = WIN_TYPE_PQOS_CMT_MONILWP;
+
+	dyn->pid = pid;
+	dyn->lwpid = lwpid;
+
+	return (dyn);
+
+L_EXIT:
+	free(dyn);
+	free(buf);
+	return (NULL);
+}
+
+static void *
+pqos_cmt_dyn_create(page_t *page, win_type_t *type)
+{
+	cmd_pqos_cmt_t *cmd_pqos = CMD_PQOS_CMT(&page->cmd);
+
+	return pqos_cmt_dyn_create_proc(page, cmd_pqos->pid,
+		cmd_pqos->lwpid, type);
+}
+
+static void
+pqos_cmt_caption_build(int lwpid, char *buf, int size)
+{
+	if (lwpid == 0)
+		snprintf(buf, size,
+			"%6s%15s%11s%11s%21s%11s",
+			CAPTION_PID, CAPTION_PROC, CAPTION_RMA, CAPTION_LMA,
+			CAPTION_LLC_OCCUPANCY, CAPTION_CPU);
+	else
+		snprintf(buf, size,
+			"%6s%15s%11s%11s%21s%11s",
+			CAPTION_LWP, CAPTION_PROC, CAPTION_RMA, CAPTION_LMA,
+			CAPTION_LLC_OCCUPANCY, CAPTION_CPU);
+}
+
+static boolean_t
+pqos_cmt_data_show(dyn_win_t *win, boolean_t *note_out)
+{
+	dyn_pqos_cmt_proc_t *dyn;
+	win_reg_t *r, *data_reg;
+	char content[WIN_LINECHAR_MAX], intval_buf[16];
+	int nprocs, nlwps, i;
+	track_proc_t *proc;
+	track_lwp_t *lwp;
+	int intval;
+	pqos_cmt_proc_line_t *lines;
+	boolean_t mbm_out = B_FALSE;
+
+	dyn = (dyn_pqos_cmt_proc_t *)(win->dyn);
+	data_reg = &dyn->data;
+
+	disp_intval(intval_buf, 16);
+
+	if (dyn->pid == 0) {
+		proc_lwp_count(&nprocs, &nlwps);
+		nprocs = MIN(nprocs, WIN_NLINES_MAX);
+		data_reg->nlines_total = nprocs;
+
+		snprintf(content, sizeof (content),
+		    "Monitoring processes with LLC occupancy (interval: %s)",
+		    intval_buf);
+	} else if (dyn->lwpid == 0) {
+		nprocs = 1;
+		data_reg->nlines_total = 1;
+
+		snprintf(content, sizeof (content),
+		    "Monitoring a process with LLC occupancy (interval: %s)",
+		    intval_buf);
+
+		mbm_out = B_TRUE;
+	} else {
+		nprocs = 1;
+		data_reg->nlines_total = 1;
+
+		snprintf(content, sizeof (content),
+		    "Monitoring a thread with LLC occupancy (interval: %s)",
+		    intval_buf);
+
+		mbm_out = B_TRUE;
+	}
+
+	r = &dyn->summary;
+	reg_erase(r);
+	reg_line_write(r, 1, ALIGN_LEFT, content);
+	dump_write("\n*** %s\n", content);
+	reg_refresh_nout(r);
+
+	/*
+	 * Display the caption of table:
+	 * "PID PROC CPU% LLC_OCCUPANCY(MB)"
+	 */
+	pqos_cmt_caption_build(dyn->lwpid, content, sizeof (content));
+
+	r = &dyn->caption;
+	reg_erase(r);
+	reg_line_write(r, 1, ALIGN_LEFT, content);
+	dump_write("%s\n", content);
+	reg_refresh_nout(r);
+
+	reg_erase(data_reg);
+	lines = (pqos_cmt_proc_line_t *)(data_reg->buf);
+
+	if (dyn->pid == 0) {
+		proc_group_lock();
+		proc_resort(SORT_KEY_CPU);
+
+		for (i = 0; i < nprocs; i++) {
+			if ((proc = proc_sort_next()) == NULL) {
+				break;
+			}
+
+			intval = proc_intval_get(proc);
+			pqos_cmt_proc_data_save(proc, NULL, intval, &lines[i]);
+		}
+
+		proc_group_unlock();
+
+	} else if (dyn->lwpid == 0) {
+		if ((proc = proc_find(dyn->pid)) == NULL) {
+			win_invalid_proc();
+			*note_out = B_TRUE;
+			return (B_FALSE);
+		}
+
+		intval = proc_intval_get(proc);
+		pqos_cmt_proc_data_save(proc, NULL, intval, &lines[0]);
+		proc_refcount_dec(proc);
+	} else {
+		if ((proc = proc_find(dyn->pid)) == NULL) {
+			win_invalid_proc();
+			*note_out = B_TRUE;
+			return (B_FALSE);
+		}
+
+		if ((lwp = proc_lwp_find(proc, dyn->lwpid)) == NULL) {
+			proc_refcount_dec(proc);
+			win_invalid_lwp();
+			*note_out = B_TRUE;
+			return (B_FALSE);
+		}
+
+		intval = lwp_intval_get(lwp);
+		pqos_cmt_proc_data_save(proc, lwp, intval, &lines[0]);
+		lwp_refcount_dec(lwp);
+		proc_refcount_dec(proc);
+	}
+
+	reg_scroll_show(data_reg, (void *)lines, nprocs,
+	    pqos_cmt_proc_str_build);
+
+	reg_refresh_nout(data_reg);
+
+	r = &dyn->hint;
+	reg_erase(r);
+
+	if (dyn->pid == 0) {
+		snprintf(content, sizeof (content),
+		    "-- Track %d active processes's LLC occupancy (marked with *) --",
+		    PERF_PQOS_CMT_MAX);
+		reg_line_write(r, 1, ALIGN_LEFT, content);
+	}
+
+	reg_line_write(r, 2, ALIGN_LEFT,
+	    "CPU%% = system CPU utilization");
+	reg_refresh_nout(r);
+
+	if (mbm_out) {
+		win_note_show(NOTE_PQOS_CMT_MONI);
+		*note_out = B_TRUE;
+	} else {
+		*note_out = B_FALSE;
+	}
+
+	return B_TRUE;
+}
+
+static boolean_t
+pqos_cmt_win_draw(dyn_win_t *win)
+{
+	boolean_t note_out, ret;
+
+	win_title_show();
+	ret = pqos_cmt_data_show(win, &note_out);
+
+	if (!note_out) {
+		win_note_show(NOTE_PQOS_CMT_TOPNPROC);
+	}
+
+	reg_update_all();
+	return (ret);
+}
+
+static void
+pqos_cmt_win_destroy(dyn_win_t *win)
+{
+	dyn_pqos_cmt_proc_t *dyn;
+
+	if ((dyn = win->dyn) != NULL) {
+		if (dyn->data.buf != NULL) {
+			free(dyn->data.buf);
+			dyn->data.buf = NULL;
+		}
+
+		reg_win_destroy(&dyn->summary);
+		reg_win_destroy(&dyn->caption);
+		reg_win_destroy(&dyn->data);
+		reg_win_destroy(&dyn->hint);
+		free(dyn);
+	}
+}
+
+static void
+pqos_cmt_win_scroll(dyn_win_t *win, int scroll_type)
+{
+	dyn_pqos_cmt_proc_t *dyn = (dyn_pqos_cmt_proc_t *)(win->dyn);
+
+	reg_line_scroll(&dyn->data, scroll_type);
+}
+
+static void
+pqos_mbm_proc_data_build(char *buf, int size,
+	pqos_mbm_proc_line_t *line)
+{
+	win_countvalue_t *value = &line->value;
+	char id[16], total_bw[16], local_bw[16];
+
+	if (line->lwpid == 0)
+		snprintf(id, sizeof(id), "%d", line->pid);
+	else
+		snprintf(id, sizeof(id), "%d", line->lwpid);
+
+	snprintf(total_bw, sizeof(total_bw), "%.1fMB",
+		ratio(line->totalbw_scaled * g_llc_total_bw_scale, 1));
+
+	snprintf(local_bw, sizeof(local_bw), "%.1fMB",
+		ratio(line->localbw_scaled * g_llc_local_bw_scale, 1));
+
+	snprintf(buf, size,
+	    "%6s%15s%10.1f%10.1f%14s%14s%9.1f",
+	    id, line->proc_name,
+	    value->rma, value->lma,
+	    total_bw, local_bw,
+	    value->cpu * 100);
+}
+
+static void
+pqos_mbm_proc_str_build(char *buf, int size, int idx, void *pv)
+{
+	pqos_mbm_proc_line_t *lines = (pqos_mbm_proc_line_t *)pv;
+	pqos_mbm_proc_line_t *line = &lines[idx];
+
+	pqos_mbm_proc_data_build(buf, size, line);
+}
+
+static void
+pqos_mbm_proc_line_get(win_reg_t *r, int idx, char *line, int size)
+{
+	pqos_mbm_proc_line_t *lines;
+
+	lines = (pqos_mbm_proc_line_t *)(r->buf);
+	pqos_mbm_proc_str_build(line, size, idx, (void *)lines);
+}
+
+static void
+pqos_mbm_proc_data_save(track_proc_t *proc, track_lwp_t *lwp, int intval,
+	pqos_mbm_proc_line_t *line)
+{
+	(void) memset(line, 0, sizeof (pqos_mbm_proc_line_t));
+
+	(void) strncpy(line->proc_name, proc->name, sizeof (line->proc_name));
+	line->proc_name[WIN_PROCNAME_SIZE - 1] = 0;
+	line->pid = proc->pid;
+	line->nlwp = proc_nlwp(proc);
+
+	if (lwp == NULL) {
+		line->totalbw_scaled = proc->pqos.totalbw_scaled;
+		line->totalbw_fd = proc->pqos.totalbw_fd;
+		line->localbw_scaled = proc->pqos.localbw_scaled;
+		line->localbw_fd = proc->pqos.localbw_fd;
+
+		win_countvalue_fill(&line->value, proc->countval_arr,
+			proc->cpuid_max, NODE_ALL, intval, g_ncpus);
+
+	} else {
+		line->totalbw_scaled = lwp->pqos.totalbw_scaled;
+		line->totalbw_fd = lwp->pqos.totalbw_fd;
+		line->localbw_scaled = lwp->pqos.localbw_scaled;
+		line->localbw_fd = lwp->pqos.localbw_fd;
+
+		win_countvalue_fill(&line->value, lwp->countval_arr,
+			lwp->cpuid_max, NODE_ALL, intval, g_ncpus);
+	}
+}
+
+static dyn_pqos_mbm_proc_t *
+pqos_mbm_dyn_create_proc(page_t *page, pid_t pid, int lwpid, win_type_t *type)
+{
+	dyn_pqos_mbm_proc_t *dyn;
+	void *buf;
+	int i;
+
+	if ((buf = zalloc(sizeof (pqos_mbm_proc_line_t) *
+	    WIN_NLINES_MAX)) == NULL) {
+		return (NULL);
+	}
+
+	if ((dyn = zalloc(sizeof (dyn_pqos_mbm_proc_t))) == NULL) {
+		free(buf);
+		return (NULL);
+	}
+
+	if ((i = reg_init(&dyn->summary, 0, 1, g_scr_width, 2, A_BOLD)) < 0)
+		goto L_EXIT;
+	if ((i = reg_init(&dyn->caption, 0, i, g_scr_width, 2, A_BOLD | A_UNDERLINE)) < 0)
+		goto L_EXIT;
+	if ((i = reg_init(&dyn->data, 0, i, g_scr_width, g_scr_height - i - 5, 0)) < 0)
+		goto L_EXIT;
+
+	reg_buf_init(&dyn->data, buf, pqos_mbm_proc_line_get);
+
+	reg_scroll_init(&dyn->data, B_TRUE);
+	(void) reg_init(&dyn->hint, 0, i, g_scr_width,
+	    g_scr_height - i - 1, A_BOLD);
+
+	if (pid == 0) {
+		/* TODO */
+	} else if (lwpid == 0)
+		*type = WIN_TYPE_PQOS_MBM_MONIPROC;
+	else
+		*type = WIN_TYPE_PQOS_MBM_MONILWP;
+
+	dyn->pid = pid;
+	dyn->lwpid = lwpid;
+
+	return (dyn);
+
+L_EXIT:
+	free(dyn);
+	free(buf);
+	return (NULL);
+}
+
+static void *
+pqos_mbm_dyn_create(page_t *page, win_type_t *type)
+{
+	cmd_pqos_mbm_t *cmd_pqos = CMD_PQOS_MBM(&page->cmd);
+
+	return pqos_mbm_dyn_create_proc(page, cmd_pqos->pid,
+		cmd_pqos->lwpid, type);
+}
+
+static void
+pqos_mbm_caption_build(int lwpid, char *buf, int size)
+{
+	if (lwpid == 0)
+		snprintf(buf, size,
+			"%6s%15s%10s%10s%14s%14s%10s",
+			CAPTION_PID, CAPTION_PROC, CAPTION_RMA, CAPTION_LMA,
+			CAPTION_TOTAL_BW, CAPTION_LOCAL_BW, CAPTION_CPU);
+	else
+		snprintf(buf, size,
+			"%6s%15s%10s%10s%14s%14s%10s",
+			CAPTION_LWP, CAPTION_PROC, CAPTION_RMA, CAPTION_LMA,
+			CAPTION_TOTAL_BW, CAPTION_LOCAL_BW, CAPTION_CPU);
+}
+
+static boolean_t
+pqos_mbm_data_show(dyn_win_t *win, boolean_t *note_out)
+{
+	dyn_pqos_mbm_proc_t *dyn;
+	win_reg_t *r, *data_reg;
+	char content[WIN_LINECHAR_MAX], intval_buf[16];
+	int nprocs;
+	track_proc_t *proc = NULL;
+	track_lwp_t *lwp = NULL;
+	int intval;
+	pqos_mbm_proc_line_t *lines;
+
+	dyn = (dyn_pqos_mbm_proc_t *)(win->dyn);
+	data_reg = &dyn->data;
+
+	disp_intval(intval_buf, 16);
+
+	if (dyn->pid == 0) {
+		/* TODO */
+	} else if (dyn->lwpid == 0) {
+		nprocs = 1;
+		data_reg->nlines_total = 1;
+
+		snprintf(content, sizeof (content),
+		    "Monitoring a process with memory bandwidth (interval: %s)",
+		    intval_buf);
+	} else {
+		nprocs = 1;
+		data_reg->nlines_total = 1;
+
+		snprintf(content, sizeof (content),
+		    "Monitoring a thread with memory bandwidth (interval: %s)",
+		    intval_buf);
+	}
+
+	r = &dyn->summary;
+	reg_erase(r);
+	reg_line_write(r, 1, ALIGN_LEFT, content);
+	dump_write("\n*** %s\n", content);
+	reg_refresh_nout(r);
+
+	pqos_mbm_caption_build(dyn->lwpid, content, sizeof (content));
+
+	r = &dyn->caption;
+	reg_erase(r);
+	reg_line_write(r, 1, ALIGN_LEFT, content);
+	dump_write("%s\n", content);
+	reg_refresh_nout(r);
+
+	reg_erase(data_reg);
+	lines = (pqos_mbm_proc_line_t *)(data_reg->buf);
+
+	if (dyn->pid == 0) {
+		/* TODO */
+	} else if (dyn->lwpid == 0) {
+		if ((proc = proc_find(dyn->pid)) == NULL) {
+			win_invalid_proc();
+			*note_out = B_TRUE;
+			return (B_FALSE);
+		}
+
+		intval = proc_intval_get(proc);
+		pqos_mbm_proc_data_save(proc, NULL, intval, &lines[0]);
+		proc_refcount_dec(proc);
+	} else {
+		if ((proc = proc_find(dyn->pid)) == NULL) {
+			win_invalid_proc();
+			*note_out = B_TRUE;
+			return (B_FALSE);
+		}
+
+		if ((lwp = proc_lwp_find(proc, dyn->lwpid)) == NULL) {
+			proc_refcount_dec(proc);
+			win_invalid_lwp();
+			*note_out = B_TRUE;
+			return (B_FALSE);
+		}
+
+		intval = lwp_intval_get(lwp);
+		pqos_mbm_proc_data_save(proc, lwp, intval, &lines[0]);
+		lwp_refcount_dec(lwp);
+		proc_refcount_dec(proc);
+	}
+
+	reg_scroll_show(data_reg, (void *)lines, nprocs,
+	    pqos_mbm_proc_str_build);
+
+	reg_refresh_nout(data_reg);
+
+	r = &dyn->hint;
+	reg_erase(r);
+
+	if (dyn->pid == 0) {
+		snprintf(content, sizeof (content),
+		    "-- Track %d active processes's LLC occupancy (marked with *) --",
+		    PERF_PQOS_CMT_MAX);
+		reg_line_write(r, 1, ALIGN_LEFT, content);
+	}
+
+	reg_line_write(r, 2, ALIGN_LEFT,
+	    "CPU%% = system CPU utilization; MBAND = Memory Bandwidth");
+	reg_refresh_nout(r);
+
+	*note_out = B_FALSE;
+
+	return B_TRUE;
+}
+
+static boolean_t
+pqos_mbm_win_draw(dyn_win_t *win)
+{
+	boolean_t note_out, ret;
+
+	win_title_show();
+	ret = pqos_mbm_data_show(win, &note_out);
+
+	if (!note_out) {
+		win_note_show(NOTE_PQOS_MBM);
+	}
+
+	reg_update_all();
+	return (ret);
+}
+
+static void
+pqos_mbm_win_destroy(dyn_win_t *win)
+{
+	dyn_pqos_mbm_proc_t *dyn;
+
+	if ((dyn = win->dyn) != NULL) {
+		if (dyn->data.buf != NULL) {
+			free(dyn->data.buf);
+			dyn->data.buf = NULL;
+		}
+
+		reg_win_destroy(&dyn->summary);
+		reg_win_destroy(&dyn->caption);
+		reg_win_destroy(&dyn->data);
+		reg_win_destroy(&dyn->hint);
+		free(dyn);
+	}
+}
+
+static void
+pqos_mbm_win_scroll(dyn_win_t *win, int scroll_type)
+{
+	dyn_pqos_mbm_proc_t *dyn = (dyn_pqos_mbm_proc_t *)(win->dyn);
+
+	reg_line_scroll(&dyn->data, scroll_type);
+}
+
 /*
  * The common entry for all warning messages.
  */
@@ -3094,6 +3736,26 @@ win_dyn_init(void *p)
 		win->scroll = os_llcallchain_win_scroll;
 		break;
 
+	case CMD_PQOS_CMT_ID:
+		if ((win->dyn = pqos_cmt_dyn_create(page, &win->type)) == NULL) {
+			goto L_EXIT;
+		}
+
+		win->draw = pqos_cmt_win_draw;
+		win->destroy = pqos_cmt_win_destroy;
+		win->scroll = pqos_cmt_win_scroll;
+		break;
+
+	case CMD_PQOS_MBM_ID:
+		if ((win->dyn = pqos_mbm_dyn_create(page, &win->type)) == NULL) {
+			goto L_EXIT;
+		}
+
+		win->draw = pqos_mbm_win_draw;
+		win->destroy = pqos_mbm_win_destroy;
+		win->scroll = pqos_mbm_win_scroll;
+		break;
+
 	default:
 		goto L_EXIT;
 	}
diff --git a/intel/wsm.c b/intel/wsm.c
index 4cd64dc..4af35e9 100644
--- a/intel/wsm.c
+++ b/intel/wsm.c
@@ -54,7 +54,7 @@ static plat_event_config_t s_wsmep_profiling[COUNT_NUM] = {
 	{ PERF_TYPE_RAW, 0x01B7, 0x53, 0x2011, "off_core_response_0" },
 	{ PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES, 0x53, 0, "cpu_clk_unhalted.ref" },
 	{ PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS, 0x53, 0, "instr_retired.any" },
-	{ PERF_TYPE_RAW, INVALID_CODE_UMASK, 0, 0, "off_core_response_1" }
+	{ PERF_TYPE_RAW, 0x01BB, 0x53, 0x5011, "off_core_response_1" }
 };
 
 static plat_event_config_t s_wsm_ll = {
-- 
2.10.2

