Blame examples/c/CMT_MBM/monitor_app.c

Packit bcb633
/*
Packit bcb633
 * BSD LICENSE
Packit bcb633
 *
Packit bcb633
 * Copyright(c) 2014-2018 Intel Corporation. All rights reserved.
Packit bcb633
 * All rights reserved.
Packit bcb633
 *
Packit bcb633
 * Redistribution and use in source and binary forms, with or without
Packit bcb633
 * modification, are permitted provided that the following conditions
Packit bcb633
 * are met:
Packit bcb633
 *
Packit bcb633
 *   * Redistributions of source code must retain the above copyright
Packit bcb633
 *     notice, this list of conditions and the following disclaimer.
Packit bcb633
 *   * Redistributions in binary form must reproduce the above copyright
Packit bcb633
 *     notice, this list of conditions and the following disclaimer in
Packit bcb633
 *     the documentation and/or other materials provided with the
Packit bcb633
 *     distribution.
Packit bcb633
 *   * Neither the name of Intel Corporation nor the names of its
Packit bcb633
 *     contributors may be used to endorse or promote products derived
Packit bcb633
 *     from this software without specific prior written permission.
Packit bcb633
 *
Packit bcb633
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit bcb633
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit bcb633
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit bcb633
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit bcb633
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit bcb633
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit bcb633
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit bcb633
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit bcb633
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit bcb633
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit bcb633
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit bcb633
 *
Packit bcb633
 */
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * @brief Platform QoS sample LLC occupancy monitoring application
Packit bcb633
 *
Packit bcb633
 */
Packit bcb633
Packit bcb633
#include <stdio.h>
Packit bcb633
#include <stdlib.h>
Packit bcb633
#include <string.h>
Packit bcb633
#include <unistd.h>
Packit bcb633
#include <sys/types.h>
Packit bcb633
#include <sys/stat.h>
Packit bcb633
#include <signal.h>
Packit bcb633
#include "pqos.h"
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * Defines
Packit bcb633
 */
Packit bcb633
#define PQOS_MAX_CORES        1024
Packit bcb633
#define PQOS_MAX_PIDS         16
Packit bcb633
#define PQOS_MAX_MON_EVENTS   1
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * Number of cores that are selected in config string
Packit bcb633
 * for monitoring LLC occupancy
Packit bcb633
 */
Packit bcb633
static int sel_monitor_num = 0;
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * The mask to tell which events to display
Packit bcb633
 */
Packit bcb633
static enum pqos_mon_event sel_events_max = (enum pqos_mon_event)0;
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * Maintains a table of core, event, number of events that are
Packit bcb633
 * selected in config string for monitoring
Packit bcb633
 */
Packit bcb633
static struct {
Packit bcb633
        unsigned core;
Packit bcb633
        struct pqos_mon_data *pgrp;
Packit bcb633
        enum pqos_mon_event events;
Packit bcb633
} sel_monitor_core_tab[PQOS_MAX_CORES];
Packit bcb633
static struct pqos_mon_data *m_mon_grps[PQOS_MAX_CORES];
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * Maintains a table of process id, event, number of events that are selected
Packit bcb633
 * in config string for monitoring LLC occupancy
Packit bcb633
 */
Packit bcb633
static struct {
Packit bcb633
        pid_t pid;
Packit bcb633
        struct pqos_mon_data *pgrp;
Packit bcb633
        enum pqos_mon_event events;
Packit bcb633
} sel_monitor_pid_tab[PQOS_MAX_PIDS];
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * Maintains the number of process id's you want to track
Packit bcb633
 */
Packit bcb633
static int sel_process_num = 0;
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * Flag to determine which library interface to use
Packit bcb633
 */
Packit bcb633
static enum pqos_interface interface = PQOS_INTER_MSR;
Packit bcb633
Packit bcb633
static void stop_monitoring(void);
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * @brief CTRL-C handler for infinite monitoring loop
Packit bcb633
 *
Packit bcb633
 * @param [in] signo signal number
Packit bcb633
 */
Packit bcb633
static void __attribute__((noreturn)) monitoring_ctrlc(int signo)
Packit bcb633
{
Packit bcb633
	printf("\nExiting[%d]...\n", signo);
Packit bcb633
        stop_monitoring();
Packit bcb633
        if (pqos_fini() != PQOS_RETVAL_OK) {
Packit bcb633
		printf("Error shutting down PQoS library!\n");
Packit bcb633
                exit(EXIT_FAILURE);
Packit bcb633
        }
Packit bcb633
	exit(EXIT_SUCCESS);
Packit bcb633
}
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * @brief Scale byte value up to KB
Packit bcb633
 *
Packit bcb633
 * @param [in] bytes value to be scaled up
Packit bcb633
 * @return scaled up value in KB's
Packit bcb633
 */
Packit bcb633
static inline double bytes_to_kb(const double bytes)
Packit bcb633
{
Packit bcb633
        return bytes / 1024.0;
Packit bcb633
}
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * @brief Scale byte value up to MB
Packit bcb633
 *
Packit bcb633
 * @param [in] bytes value to be scaled up
Packit bcb633
 * @return scaled up value in MB's
Packit bcb633
 */
Packit bcb633
static inline double bytes_to_mb(const double bytes)
Packit bcb633
{
Packit bcb633
        return bytes / (1024.0 * 1024.0);
Packit bcb633
}
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * @brief Check to determine if processes or cores are monitored
Packit bcb633
 *
Packit bcb633
 * @return Process monitoring mode status
Packit bcb633
 * @retval 0 monitoring cores
Packit bcb633
 * @retval 1 monitoring processes
Packit bcb633
 */
Packit bcb633
static inline int process_mode(void)
Packit bcb633
{
Packit bcb633
        return (sel_process_num <= 0) ? 0 : 1;
Packit bcb633
}
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * @brief Verifies and translates monitoring config string into
Packit bcb633
 *        internal monitoring configuration.
Packit bcb633
 *
Packit bcb633
 * @param [in] argc Number of arguments in input command
Packit bcb633
 * @param [in] argv Input arguments for LLC occupancy monitoring
Packit bcb633
 */
Packit bcb633
static void
Packit bcb633
monitoring_get_input(int argc, char *argv[])
Packit bcb633
{
Packit bcb633
	int num_args, num_opts = 1, i = 0, sel_pid = 0, help = 0;
Packit bcb633
Packit bcb633
        for (i = 0; i < argc; i++) {
Packit bcb633
                if (!strcmp(argv[i], "-p")) {
Packit bcb633
                        sel_pid = 1;
Packit bcb633
                        num_opts++;
Packit bcb633
                } else if (!strcmp(argv[i], "-I")) {
Packit bcb633
                        interface = PQOS_INTER_OS;
Packit bcb633
                        num_opts++;
Packit bcb633
                } else if (!strcmp(argv[i], "-H") || !strcmp(argv[i], "-h")) {
Packit bcb633
                        help = 1;
Packit bcb633
                        num_opts++;
Packit bcb633
                }
Packit bcb633
        }
Packit bcb633
        /* Ensure OS interface selected if monitoring tasks */
Packit bcb633
        if (sel_pid && interface == PQOS_INTER_MSR) {
Packit bcb633
                printf("Error: PID monitoring requires OS interface "
Packit bcb633
                        "selection!\nPlease use the -I option.\n");
Packit bcb633
                help = 1;
Packit bcb633
        }
Packit bcb633
        num_args = (argc - num_opts);
Packit bcb633
        if (help) {
Packit bcb633
		printf("Usage:  %s [<core1> <core2> <core3> ...]\n"
Packit bcb633
                       "        %s -I -p [<pid1> <pid2> <pid3> ...]\n",
Packit bcb633
                       argv[0], argv[0]);
Packit bcb633
		printf("Eg   :  %s 1 2 6\n        "
Packit bcb633
                       "%s -I -p 3564 7638 356\n"
Packit bcb633
                       "Notes:\n        "
Packit bcb633
                       "-h      help\n        "
Packit bcb633
                       "-I      select library OS interface\n        "
Packit bcb633
                       "-p      select process ID's to monitor LLC occupancy"
Packit bcb633
                       "\n\n", argv[0], argv[0]);
Packit bcb633
		exit(EXIT_SUCCESS);
Packit bcb633
        } else if (num_args == 0) {
Packit bcb633
		sel_monitor_num = 0;
Packit bcb633
        } else {
Packit bcb633
                if (sel_pid) {
Packit bcb633
                        if (num_args > PQOS_MAX_PIDS)
Packit bcb633
                                num_args = PQOS_MAX_PIDS;
Packit bcb633
                        for (i = 0; i < num_args; i++) {
Packit bcb633
                                m_mon_grps[i] = malloc(sizeof(**m_mon_grps));
Packit bcb633
                                sel_monitor_pid_tab[i].pgrp = m_mon_grps[i];
Packit bcb633
                                sel_monitor_pid_tab[i].pid =
Packit bcb633
                                        (unsigned) atoi(argv[num_opts + i]);
Packit bcb633
                        }
Packit bcb633
                        sel_process_num = (int) num_args;
Packit bcb633
                } else {
Packit bcb633
                        if (num_args > PQOS_MAX_CORES)
Packit bcb633
                                num_args = PQOS_MAX_CORES;
Packit bcb633
                        for (i = 0; i < num_args; i++) {
Packit bcb633
                                m_mon_grps[i] = malloc(sizeof(**m_mon_grps));
Packit bcb633
                                sel_monitor_core_tab[i].pgrp = m_mon_grps[i];
Packit bcb633
                                sel_monitor_core_tab[i].core =
Packit bcb633
                                        (unsigned) atoi(argv[num_opts + i]);
Packit bcb633
                        }
Packit bcb633
                        sel_monitor_num = (int) num_args;
Packit bcb633
                }
Packit bcb633
	}
Packit bcb633
}
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * @brief Starts monitoring on selected cores/PIDs
Packit bcb633
 *
Packit bcb633
 * @param [in] cpu_info cpu information structure
Packit bcb633
 * @param [in] cap_mon monitoring capabilities structure
Packit bcb633
 *
Packit bcb633
 * @return Operation status
Packit bcb633
 * @retval 0 OK
Packit bcb633
 * @retval -1 error
Packit bcb633
 */
Packit bcb633
static int
Packit bcb633
setup_monitoring(const struct pqos_cpuinfo *cpu_info,
Packit bcb633
                 const struct pqos_capability * const cap_mon)
Packit bcb633
{
Packit bcb633
	unsigned i;
Packit bcb633
        const enum pqos_mon_event perf_events = (enum pqos_mon_event)
Packit bcb633
            (PQOS_PERF_EVENT_IPC | PQOS_PERF_EVENT_LLC_MISS);
Packit bcb633
Packit bcb633
        for (i = 0; (unsigned)i < cap_mon->u.mon->num_events; i++)
Packit bcb633
                sel_events_max |= (cap_mon->u.mon->events[i].type);
Packit bcb633
Packit bcb633
        /* Remove perf events IPC and LLC MISSES */
Packit bcb633
        sel_events_max &= ~perf_events;
Packit bcb633
        if (sel_monitor_num == 0 && sel_process_num == 0) {
Packit bcb633
                for (i = 0; i < cpu_info->num_cores; i++) {
Packit bcb633
                        unsigned lcore = cpu_info->cores[i].lcore;
Packit bcb633
Packit bcb633
                        sel_monitor_core_tab[sel_monitor_num].core = lcore;
Packit bcb633
                        sel_monitor_core_tab[sel_monitor_num].events =
Packit bcb633
                                sel_events_max;
Packit bcb633
                        m_mon_grps[sel_monitor_num] =
Packit bcb633
                                malloc(sizeof(**m_mon_grps));
Packit bcb633
                        sel_monitor_core_tab[sel_monitor_num].pgrp =
Packit bcb633
                                m_mon_grps[sel_monitor_num];
Packit bcb633
                        sel_monitor_num++;
Packit bcb633
                }
Packit bcb633
        }
Packit bcb633
        if (!process_mode()) {
Packit bcb633
                for (i = 0; i < (unsigned) sel_monitor_num; i++) {
Packit bcb633
                        unsigned lcore = sel_monitor_core_tab[i].core;
Packit bcb633
                        int ret;
Packit bcb633
Packit bcb633
                        ret = pqos_mon_start(1, &lcore,
Packit bcb633
                                             sel_events_max,
Packit bcb633
                                             NULL,
Packit bcb633
                                             sel_monitor_core_tab[i].pgrp);
Packit bcb633
                        if (ret != PQOS_RETVAL_OK) {
Packit bcb633
                                printf("Monitoring start error on core %u,"
Packit bcb633
                                       "status %d\n", lcore, ret);
Packit bcb633
                                return ret;
Packit bcb633
                        }
Packit bcb633
                }
Packit bcb633
        } else {
Packit bcb633
                for (i = 0; i < (unsigned) sel_process_num; i++) {
Packit bcb633
                        pid_t pid = sel_monitor_pid_tab[i].pid;
Packit bcb633
                        int ret;
Packit bcb633
Packit bcb633
                        ret = pqos_mon_start_pids(1, &pid,
Packit bcb633
                                                 PQOS_MON_EVENT_L3_OCCUP,
Packit bcb633
                                                 NULL,
Packit bcb633
                                                 sel_monitor_pid_tab[i].pgrp);
Packit bcb633
                        if (ret != PQOS_RETVAL_OK) {
Packit bcb633
                                printf("Monitoring start error on pid %u,"
Packit bcb633
                                       "status %d\n", pid, ret);
Packit bcb633
                                return ret;
Packit bcb633
                        }
Packit bcb633
                }
Packit bcb633
        }
Packit bcb633
	return PQOS_RETVAL_OK;
Packit bcb633
}
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * @brief Stops monitoring on selected cores
Packit bcb633
 *
Packit bcb633
 */
Packit bcb633
static void stop_monitoring(void)
Packit bcb633
{
Packit bcb633
	unsigned i, mon_number = 0;
Packit bcb633
Packit bcb633
        if (!process_mode())
Packit bcb633
                mon_number = (unsigned) sel_monitor_num;
Packit bcb633
        else
Packit bcb633
                mon_number = (unsigned) sel_process_num;
Packit bcb633
Packit bcb633
	for (i = 0; i < mon_number; i++) {
Packit bcb633
                int ret;
Packit bcb633
Packit bcb633
		ret = pqos_mon_stop(m_mon_grps[i]);
Packit bcb633
		if (ret != PQOS_RETVAL_OK)
Packit bcb633
			printf("Monitoring stop error!\n");
Packit bcb633
                free(m_mon_grps[i]);
Packit bcb633
	}
Packit bcb633
}
Packit bcb633
Packit bcb633
/**
Packit bcb633
 * @brief Reads monitoring event data
Packit bcb633
 */
Packit bcb633
static void monitoring_loop(void)
Packit bcb633
{
Packit bcb633
        unsigned mon_number = 0;
Packit bcb633
	int ret = PQOS_RETVAL_OK;
Packit bcb633
	int i = 0;
Packit bcb633
Packit bcb633
	if (signal(SIGINT, monitoring_ctrlc) == SIG_ERR)
Packit bcb633
		printf("Failed to catch SIGINT!\n");
Packit bcb633
Packit bcb633
        if (!process_mode())
Packit bcb633
	        mon_number = (unsigned) sel_monitor_num;
Packit bcb633
	else
Packit bcb633
	        mon_number = (unsigned) sel_process_num;
Packit bcb633
Packit bcb633
	while (1) {
Packit bcb633
                ret = pqos_mon_poll(m_mon_grps, (unsigned)mon_number);
Packit bcb633
                if (ret != PQOS_RETVAL_OK) {
Packit bcb633
                        printf("Failed to poll monitoring data!\n");
Packit bcb633
                        return;
Packit bcb633
                }
Packit bcb633
                if (!process_mode()) {
Packit bcb633
                        printf("    CORE     RMID    LLC[KB]"
Packit bcb633
                               "    MBL[MB]    MBR[MB]\n");
Packit bcb633
                        for (i = 0; i < sel_monitor_num; i++) {
Packit bcb633
                                const struct pqos_event_values *pv =
Packit bcb633
                                        &m_mon_grps[i]->values;
Packit bcb633
                                double llc = bytes_to_kb(pv->llc);
Packit bcb633
                                double mbr = bytes_to_mb(pv->mbm_remote_delta);
Packit bcb633
                                double mbl = bytes_to_mb(pv->mbm_local_delta);
Packit bcb633
Packit bcb633
                                if (interface == PQOS_INTER_OS)
Packit bcb633
                                        printf("%8u %s %10.1f %10.1f %10.1f\n",
Packit bcb633
                                               m_mon_grps[i]->cores[0],
Packit bcb633
                                               "     N/A", llc, mbl, mbr);
Packit bcb633
                                else
Packit bcb633
                                        printf("%8u %8u %10.1f %10.1f %10.1f\n",
Packit bcb633
                                               m_mon_grps[i]->cores[0],
Packit bcb633
                                               m_mon_grps[i]->poll_ctx[0].rmid,
Packit bcb633
                                               llc, mbl, mbr);
Packit bcb633
                        }
Packit bcb633
                } else {
Packit bcb633
                        printf("PID       LLC[KB]\n");
Packit bcb633
                        for (i = 0; i < sel_process_num; i++) {
Packit bcb633
                                const struct pqos_event_values *pv =
Packit bcb633
                                        &m_mon_grps[i]->values;
Packit bcb633
                                double llc = bytes_to_kb(pv->llc);
Packit bcb633
Packit bcb633
                                printf("%6d %10.1f\n",
Packit bcb633
                                       m_mon_grps[i]->pids[0], llc);
Packit bcb633
                        }
Packit bcb633
                }
Packit bcb633
		printf("\nPress Enter to continue or Ctrl+c to exit");
Packit bcb633
		if (getchar() != '\n')
Packit bcb633
			break;
Packit bcb633
		printf("\e[1;1H\e[2J");
Packit bcb633
	}
Packit bcb633
}
Packit bcb633
Packit bcb633
int main(int argc, char *argv[])
Packit bcb633
{
Packit bcb633
	struct pqos_config config;
Packit bcb633
	const struct pqos_cpuinfo *p_cpu = NULL;
Packit bcb633
	const struct pqos_cap *p_cap = NULL;
Packit bcb633
	int ret, exit_val = EXIT_SUCCESS;
Packit bcb633
	const struct pqos_capability *cap_mon = NULL;
Packit bcb633
Packit bcb633
        /* Get input from user */
Packit bcb633
	monitoring_get_input(argc, argv);
Packit bcb633
Packit bcb633
        memset(&config, 0, sizeof(config));
Packit bcb633
        config.fd_log = STDOUT_FILENO;
Packit bcb633
        config.verbose = 0;
Packit bcb633
        config.interface = interface;
Packit bcb633
Packit bcb633
	/* PQoS Initialization - Check and initialize CAT and CMT capability */
Packit bcb633
	ret = pqos_init(&config);
Packit bcb633
	if (ret != PQOS_RETVAL_OK) {
Packit bcb633
		printf("Error initializing PQoS library!\n");
Packit bcb633
		exit_val = EXIT_FAILURE;
Packit bcb633
		goto error_exit;
Packit bcb633
	}
Packit bcb633
	/* Get CMT capability and CPU info pointer */
Packit bcb633
	ret = pqos_cap_get(&p_cap, &p_cpu);
Packit bcb633
	if (ret != PQOS_RETVAL_OK) {
Packit bcb633
		printf("Error retrieving PQoS capabilities!\n");
Packit bcb633
		exit_val = EXIT_FAILURE;
Packit bcb633
		goto error_exit;
Packit bcb633
	}
Packit bcb633
	(void) pqos_cap_get_type(p_cap, PQOS_CAP_TYPE_MON, &cap_mon);
Packit bcb633
	/* Setup the monitoring resources */
Packit bcb633
	ret = setup_monitoring(p_cpu, cap_mon);
Packit bcb633
	if (ret != PQOS_RETVAL_OK) {
Packit bcb633
		printf("Error Setting up monitoring!\n");
Packit bcb633
                exit_val = EXIT_FAILURE;
Packit bcb633
                goto error_exit;
Packit bcb633
        }
Packit bcb633
	/* Start Monitoring */
Packit bcb633
	monitoring_loop();
Packit bcb633
	/* Stop Monitoring */
Packit bcb633
	stop_monitoring();
Packit bcb633
 error_exit:
Packit bcb633
	ret = pqos_fini();
Packit bcb633
	if (ret != PQOS_RETVAL_OK)
Packit bcb633
		printf("Error shutting down PQoS library!\n");
Packit bcb633
	return exit_val;
Packit bcb633
}