/*
* BSD LICENSE
*
* Copyright(c) 2014-2018 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @brief Set of utility functions to operate on Platform QoS (pqos) data
* structures.
*
* These functions need no synchronization mechanisms.
*
*/
#include <stdlib.h>
#include <string.h>
#ifdef __linux__
#include <alloca.h> /* alloca() */
#endif /* __linux__ */
#include "pqos.h"
#include "types.h"
#include "utils.h"
#define TOPO_OBJ_SOCKET 0
#define TOPO_OBJ_L2_CLUSTER 2
#define TOPO_OBJ_L3_CLUSTER 3
static int m_interface = PQOS_INTER_MSR;
int
_pqos_utils_init(int interface)
{
if (interface == PQOS_INTER_OS_RESCTRL_MON)
m_interface = PQOS_INTER_OS;
else
m_interface = interface;
return PQOS_RETVAL_OK;
}
unsigned *
pqos_cpu_get_sockets(const struct pqos_cpuinfo *cpu,
unsigned *count)
{
unsigned scount = 0, i = 0;
unsigned *sockets = NULL;
ASSERT(cpu != NULL);
ASSERT(count != NULL);
if (cpu == NULL || count == NULL)
return NULL;
sockets = (unsigned *) malloc(sizeof(sockets[0]) * cpu->num_cores);
if (sockets == NULL)
return NULL;
for (i = 0; i < cpu->num_cores; i++) {
unsigned j = 0;
/**
* Check if this socket id is already on the \a sockets list
*/
for (j = 0; j < scount && scount > 0; j++)
if (cpu->cores[i].socket == sockets[j])
break;
if (j >= scount || scount == 0) {
/**
* This socket wasn't reported before
*/
sockets[scount++] = cpu->cores[i].socket;
}
}
*count = scount;
return sockets;
}
unsigned *
pqos_cpu_get_l2ids(const struct pqos_cpuinfo *cpu,
unsigned *count)
{
unsigned l2count = 0, i = 0;
unsigned *l2ids = NULL;
ASSERT(cpu != NULL);
ASSERT(count != NULL);
if (cpu == NULL || count == NULL)
return NULL;
l2ids = (unsigned *) malloc(sizeof(l2ids[0]) * cpu->num_cores);
if (l2ids == NULL)
return NULL;
for (i = 0; i < cpu->num_cores; i++) {
unsigned j = 0;
/**
* Check if this L2 id is already on the list
*/
for (j = 0; j < l2count && l2count > 0; j++)
if (cpu->cores[i].l2_id == l2ids[j])
break;
if (j >= l2count || l2count == 0) {
/**
* This l2id wasn't reported before
*/
l2ids[l2count++] = cpu->cores[i].l2_id;
}
}
*count = l2count;
return l2ids;
}
/**
* @brief Creates list of cores belonging to given topology object
*
* @param [in] cpu CPU topology
* @param [in] type CPU topology object type to search cores for
* TOPO_OBJ_SOCKET - sockets
* TOPO_OBJ_L2_CLUSTER - L2 cache clusters
* TOPO_OBJ_L3_CLUSTER - L3 cache clusters
* @param [in] id CPU topology object ID to search cores for
* @param [out] count place to put number of objects found
*
* @return Pointer to list of cores for given topology object
* @retval NULL on error or if no core found
*/
static unsigned *
__get_cores_per_topology_obj(const struct pqos_cpuinfo *cpu,
const int type,
const unsigned id,
unsigned *count)
{
unsigned num = 0, i = 0;
unsigned *core_list = NULL;
ASSERT(cpu != NULL);
ASSERT(count != NULL);
if (cpu == NULL || count == NULL)
return NULL;
core_list = (unsigned *) malloc(cpu->num_cores * sizeof(core_list[0]));
if (core_list == NULL)
return NULL;
for (i = 0; i < cpu->num_cores; i++)
if ((type == TOPO_OBJ_L3_CLUSTER &&
id == cpu->cores[i].l3_id) ||
(type == TOPO_OBJ_L2_CLUSTER &&
id == cpu->cores[i].l2_id) ||
(type == TOPO_OBJ_SOCKET && id == cpu->cores[i].socket))
core_list[num++] = cpu->cores[i].lcore;
if (num == 0) {
free(core_list);
return NULL;
}
*count = num;
return core_list;
}
unsigned *
pqos_cpu_get_cores_l3id(const struct pqos_cpuinfo *cpu, const unsigned l3_id,
unsigned *count)
{
return __get_cores_per_topology_obj(cpu, TOPO_OBJ_L3_CLUSTER, l3_id,
count);
}
unsigned *
pqos_cpu_get_cores(const struct pqos_cpuinfo *cpu,
const unsigned socket,
unsigned *count)
{
unsigned i = 0, cnt = 0;
unsigned *cores = NULL;
ASSERT(cpu != NULL);
ASSERT(count != NULL);
if (cpu == NULL || count == NULL)
return NULL;
cores = (unsigned *) malloc(cpu->num_cores * sizeof(cores[0]));
if (cores == NULL)
return NULL;
for (i = 0; i < cpu->num_cores; i++)
if (cpu->cores[i].socket == socket)
cores[cnt++] = cpu->cores[i].lcore;
if (!cnt) {
free(cores);
return NULL;
}
*count = cnt;
return cores;
}
const struct pqos_coreinfo *
pqos_cpu_get_core_info(const struct pqos_cpuinfo *cpu, unsigned lcore)
{
unsigned i;
ASSERT(cpu != NULL);
if (cpu == NULL)
return NULL;
for (i = 0; i < cpu->num_cores; i++)
if (cpu->cores[i].lcore == lcore)
return &cpu->cores[i];
return NULL;
}
int
pqos_cpu_get_one_core(const struct pqos_cpuinfo *cpu,
const unsigned socket,
unsigned *lcore)
{
unsigned i = 0;
ASSERT(cpu != NULL);
ASSERT(lcore != NULL);
if (cpu == NULL || lcore == NULL)
return PQOS_RETVAL_PARAM;
for (i = 0; i < cpu->num_cores; i++)
if (cpu->cores[i].socket == socket) {
*lcore = cpu->cores[i].lcore;
return PQOS_RETVAL_OK;
}
return PQOS_RETVAL_ERROR;
}
int
pqos_cpu_get_one_by_l2id(const struct pqos_cpuinfo *cpu,
const unsigned l2id,
unsigned *lcore)
{
unsigned i = 0;
ASSERT(cpu != NULL);
ASSERT(lcore != NULL);
if (cpu == NULL || lcore == NULL)
return PQOS_RETVAL_PARAM;
for (i = 0; i < cpu->num_cores; i++)
if (cpu->cores[i].l2_id == l2id) {
*lcore = cpu->cores[i].lcore;
return PQOS_RETVAL_OK;
}
return PQOS_RETVAL_ERROR;
}
int
pqos_cpu_check_core(const struct pqos_cpuinfo *cpu,
const unsigned lcore)
{
unsigned i = 0;
ASSERT(cpu != NULL);
if (cpu == NULL)
return PQOS_RETVAL_PARAM;
for (i = 0; i < cpu->num_cores; i++)
if (cpu->cores[i].lcore == lcore)
return PQOS_RETVAL_OK;
return PQOS_RETVAL_ERROR;
}
int
pqos_cpu_get_socketid(const struct pqos_cpuinfo *cpu,
const unsigned lcore,
unsigned *socket)
{
unsigned i = 0;
if (cpu == NULL || socket == NULL)
return PQOS_RETVAL_PARAM;
for (i = 0; i < cpu->num_cores; i++)
if (cpu->cores[i].lcore == lcore) {
*socket = cpu->cores[i].socket;
return PQOS_RETVAL_OK;
}
return PQOS_RETVAL_ERROR;
}
int
pqos_cpu_get_clusterid(const struct pqos_cpuinfo *cpu,
const unsigned lcore,
unsigned *cluster)
{
unsigned i = 0;
if (cpu == NULL || cluster == NULL)
return PQOS_RETVAL_PARAM;
for (i = 0; i < cpu->num_cores; i++)
if (cpu->cores[i].lcore == lcore) {
*cluster = cpu->cores[i].l3_id;
return PQOS_RETVAL_OK;
}
return PQOS_RETVAL_ERROR;
}
int
pqos_cap_get_type(const struct pqos_cap *cap,
const enum pqos_cap_type type,
const struct pqos_capability **cap_item)
{
int ret = PQOS_RETVAL_RESOURCE;
unsigned i;
ASSERT(cap != NULL && cap_item != NULL);
if (cap == NULL || cap_item == NULL)
return PQOS_RETVAL_PARAM;
ASSERT(type < PQOS_CAP_TYPE_NUMOF);
if (type >= PQOS_CAP_TYPE_NUMOF)
return PQOS_RETVAL_PARAM;
for (i = 0; i < cap->num_cap; i++) {
if (cap->capabilities[i].type != type)
continue;
/**
* Feature not supported for OS interface
*/
if (m_interface == PQOS_INTER_OS &&
!cap->capabilities[i].os_support)
continue;
*cap_item = &cap->capabilities[i];
ret = PQOS_RETVAL_OK;
break;
}
return ret;
}
int
pqos_cap_get_event(const struct pqos_cap *cap,
const enum pqos_mon_event event,
const struct pqos_monitor **p_mon)
{
const struct pqos_capability *cap_item = NULL;
const struct pqos_cap_mon *mon = NULL;
int ret = PQOS_RETVAL_OK;
unsigned i;
if (cap == NULL || p_mon == NULL)
return PQOS_RETVAL_PARAM;
ret = pqos_cap_get_type(cap, PQOS_CAP_TYPE_MON, &cap_item);
if (ret != PQOS_RETVAL_OK)
return ret;
ASSERT(cap_item != NULL);
mon = cap_item->u.mon;
ret = PQOS_RETVAL_ERROR;
for (i = 0; i < mon->num_events; i++) {
if (mon->events[i].type != event)
continue;
/**
* Feature not supported for OS interface
*/
if (m_interface == PQOS_INTER_OS && !mon->events[i].os_support)
continue;
*p_mon = &mon->events[i];
ret = PQOS_RETVAL_OK;
break;
}
return ret;
}
int
pqos_l3ca_get_cos_num(const struct pqos_cap *cap,
unsigned *cos_num)
{
const struct pqos_capability *item = NULL;
int ret = PQOS_RETVAL_OK;
ASSERT(cap != NULL && cos_num != NULL);
if (cap == NULL || cos_num == NULL)
return PQOS_RETVAL_PARAM;
ret = pqos_cap_get_type(cap, PQOS_CAP_TYPE_L3CA, &item);
if (ret != PQOS_RETVAL_OK)
return ret; /**< no L3CA capability */
ASSERT(item != NULL);
*cos_num = item->u.l3ca->num_classes;
return ret;
}
int
pqos_l2ca_get_cos_num(const struct pqos_cap *cap,
unsigned *cos_num)
{
const struct pqos_capability *item = NULL;
int ret = PQOS_RETVAL_OK;
ASSERT(cap != NULL && cos_num != NULL);
if (cap == NULL || cos_num == NULL)
return PQOS_RETVAL_PARAM;
ret = pqos_cap_get_type(cap, PQOS_CAP_TYPE_L2CA, &item);
if (ret != PQOS_RETVAL_OK)
return ret; /**< no L2CA capability */
ASSERT(item != NULL);
*cos_num = item->u.l2ca->num_classes;
return ret;
}
int
pqos_mba_get_cos_num(const struct pqos_cap *cap,
unsigned *cos_num)
{
const struct pqos_capability *item = NULL;
int ret = PQOS_RETVAL_OK;
ASSERT(cap != NULL && cos_num != NULL);
if (cap == NULL || cos_num == NULL)
return PQOS_RETVAL_PARAM;
ret = pqos_cap_get_type(cap, PQOS_CAP_TYPE_MBA, &item);
if (ret != PQOS_RETVAL_OK)
return ret; /**< no MBA capability */
ASSERT(item != NULL);
*cos_num = item->u.mba->num_classes;
return ret;
}
int
pqos_l3ca_cdp_enabled(const struct pqos_cap *cap,
int *cdp_supported,
int *cdp_enabled)
{
const struct pqos_capability *item = NULL;
int ret = PQOS_RETVAL_OK;
ASSERT(cap != NULL && (cdp_enabled != NULL || cdp_supported != NULL));
if (cap == NULL || (cdp_enabled == NULL && cdp_supported == NULL))
return PQOS_RETVAL_PARAM;
ret = pqos_cap_get_type(cap, PQOS_CAP_TYPE_L3CA, &item);
if (ret != PQOS_RETVAL_OK)
return ret; /**< no L3CA capability */
ASSERT(item != NULL);
if (cdp_supported != NULL) {
if (m_interface == PQOS_INTER_MSR)
*cdp_supported = item->u.l3ca->cdp;
else if (m_interface == PQOS_INTER_OS)
*cdp_supported = item->u.l3ca->os_cdp;
}
if (cdp_enabled != NULL)
*cdp_enabled = item->u.l3ca->cdp_on;
return ret;
}
int
pqos_l2ca_cdp_enabled(const struct pqos_cap *cap,
int *cdp_supported,
int *cdp_enabled)
{
const struct pqos_capability *l2ca = NULL;
int ret = PQOS_RETVAL_OK;
ASSERT(cap != NULL && (cdp_enabled != NULL || cdp_supported != NULL));
if (cap == NULL || (cdp_enabled == NULL && cdp_supported == NULL))
return PQOS_RETVAL_PARAM;
ret = pqos_cap_get_type(cap, PQOS_CAP_TYPE_L2CA, &l2ca);
if (ret != PQOS_RETVAL_OK)
return ret; /**< no L2CA capability */
ASSERT(l2ca != NULL);
if (cdp_supported != NULL) {
if (m_interface == PQOS_INTER_MSR)
*cdp_supported = l2ca->u.l2ca->cdp;
else if (m_interface == PQOS_INTER_OS)
*cdp_supported = l2ca->u.l2ca->os_cdp;
}
if (cdp_enabled != NULL)
*cdp_enabled = l2ca->u.l2ca->cdp_on;
return ret;
}